update prometheus dependencies (#5520)
Signed-off-by: junot <junotxiang@kubesphere.io>
This commit is contained in:
41
vendor/github.com/prometheus/alertmanager/api/v2/client/alert/alert_client.go
generated
vendored
41
vendor/github.com/prometheus/alertmanager/api/v2/client/alert/alert_client.go
generated
vendored
@@ -23,12 +23,11 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// New creates a new alert API client.
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) *Client {
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService {
|
||||
return &Client{transport: transport, formats: formats}
|
||||
}
|
||||
|
||||
@@ -40,16 +39,27 @@ type Client struct {
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// ClientOption is the option for Client methods
|
||||
type ClientOption func(*runtime.ClientOperation)
|
||||
|
||||
// ClientService is the interface for Client methods
|
||||
type ClientService interface {
|
||||
GetAlerts(params *GetAlertsParams, opts ...ClientOption) (*GetAlertsOK, error)
|
||||
|
||||
PostAlerts(params *PostAlertsParams, opts ...ClientOption) (*PostAlertsOK, error)
|
||||
|
||||
SetTransport(transport runtime.ClientTransport)
|
||||
}
|
||||
|
||||
/*
|
||||
GetAlerts Get a list of alerts
|
||||
*/
|
||||
func (a *Client) GetAlerts(params *GetAlertsParams) (*GetAlertsOK, error) {
|
||||
func (a *Client) GetAlerts(params *GetAlertsParams, opts ...ClientOption) (*GetAlertsOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewGetAlertsParams()
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(&runtime.ClientOperation{
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "getAlerts",
|
||||
Method: "GET",
|
||||
PathPattern: "/alerts",
|
||||
@@ -60,7 +70,12 @@ func (a *Client) GetAlerts(params *GetAlertsParams) (*GetAlertsOK, error) {
|
||||
Reader: &GetAlertsReader{formats: a.formats},
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
})
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -77,13 +92,12 @@ func (a *Client) GetAlerts(params *GetAlertsParams) (*GetAlertsOK, error) {
|
||||
/*
|
||||
PostAlerts Create new Alerts
|
||||
*/
|
||||
func (a *Client) PostAlerts(params *PostAlertsParams) (*PostAlertsOK, error) {
|
||||
func (a *Client) PostAlerts(params *PostAlertsParams, opts ...ClientOption) (*PostAlertsOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewPostAlertsParams()
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(&runtime.ClientOperation{
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "postAlerts",
|
||||
Method: "POST",
|
||||
PathPattern: "/alerts",
|
||||
@@ -94,7 +108,12 @@ func (a *Client) PostAlerts(params *PostAlertsParams) (*PostAlertsOK, error) {
|
||||
Reader: &PostAlertsReader{formats: a.formats},
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
})
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
187
vendor/github.com/prometheus/alertmanager/api/v2/client/alert/get_alerts_parameters.go
generated
vendored
187
vendor/github.com/prometheus/alertmanager/api/v2/client/alert/get_alerts_parameters.go
generated
vendored
@@ -27,119 +27,96 @@ import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// NewGetAlertsParams creates a new GetAlertsParams object
|
||||
// with the default values initialized.
|
||||
// NewGetAlertsParams creates a new GetAlertsParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewGetAlertsParams() *GetAlertsParams {
|
||||
var (
|
||||
activeDefault = bool(true)
|
||||
inhibitedDefault = bool(true)
|
||||
silencedDefault = bool(true)
|
||||
unprocessedDefault = bool(true)
|
||||
)
|
||||
return &GetAlertsParams{
|
||||
Active: &activeDefault,
|
||||
Inhibited: &inhibitedDefault,
|
||||
Silenced: &silencedDefault,
|
||||
Unprocessed: &unprocessedDefault,
|
||||
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetAlertsParamsWithTimeout creates a new GetAlertsParams object
|
||||
// with the default values initialized, and the ability to set a timeout on a request
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewGetAlertsParamsWithTimeout(timeout time.Duration) *GetAlertsParams {
|
||||
var (
|
||||
activeDefault = bool(true)
|
||||
inhibitedDefault = bool(true)
|
||||
silencedDefault = bool(true)
|
||||
unprocessedDefault = bool(true)
|
||||
)
|
||||
return &GetAlertsParams{
|
||||
Active: &activeDefault,
|
||||
Inhibited: &inhibitedDefault,
|
||||
Silenced: &silencedDefault,
|
||||
Unprocessed: &unprocessedDefault,
|
||||
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetAlertsParamsWithContext creates a new GetAlertsParams object
|
||||
// with the default values initialized, and the ability to set a context for a request
|
||||
// with the ability to set a context for a request.
|
||||
func NewGetAlertsParamsWithContext(ctx context.Context) *GetAlertsParams {
|
||||
var (
|
||||
activeDefault = bool(true)
|
||||
inhibitedDefault = bool(true)
|
||||
silencedDefault = bool(true)
|
||||
unprocessedDefault = bool(true)
|
||||
)
|
||||
return &GetAlertsParams{
|
||||
Active: &activeDefault,
|
||||
Inhibited: &inhibitedDefault,
|
||||
Silenced: &silencedDefault,
|
||||
Unprocessed: &unprocessedDefault,
|
||||
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetAlertsParamsWithHTTPClient creates a new GetAlertsParams object
|
||||
// with the default values initialized, and the ability to set a custom HTTPClient for a request
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewGetAlertsParamsWithHTTPClient(client *http.Client) *GetAlertsParams {
|
||||
var (
|
||||
activeDefault = bool(true)
|
||||
inhibitedDefault = bool(true)
|
||||
silencedDefault = bool(true)
|
||||
unprocessedDefault = bool(true)
|
||||
)
|
||||
return &GetAlertsParams{
|
||||
Active: &activeDefault,
|
||||
Inhibited: &inhibitedDefault,
|
||||
Silenced: &silencedDefault,
|
||||
Unprocessed: &unprocessedDefault,
|
||||
HTTPClient: client,
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*GetAlertsParams contains all the parameters to send to the API endpoint
|
||||
for the get alerts operation typically these are written to a http.Request
|
||||
/*
|
||||
GetAlertsParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the get alerts operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type GetAlertsParams struct {
|
||||
|
||||
/*Active
|
||||
Show active alerts
|
||||
/* Active.
|
||||
|
||||
Show active alerts
|
||||
|
||||
Default: true
|
||||
*/
|
||||
Active *bool
|
||||
/*Filter
|
||||
A list of matchers to filter alerts by
|
||||
|
||||
/* Filter.
|
||||
|
||||
A list of matchers to filter alerts by
|
||||
*/
|
||||
Filter []string
|
||||
/*Inhibited
|
||||
Show inhibited alerts
|
||||
|
||||
/* Inhibited.
|
||||
|
||||
Show inhibited alerts
|
||||
|
||||
Default: true
|
||||
*/
|
||||
Inhibited *bool
|
||||
/*Receiver
|
||||
A regex matching receivers to filter alerts by
|
||||
|
||||
/* Receiver.
|
||||
|
||||
A regex matching receivers to filter alerts by
|
||||
*/
|
||||
Receiver *string
|
||||
/*Silenced
|
||||
Show silenced alerts
|
||||
|
||||
/* Silenced.
|
||||
|
||||
Show silenced alerts
|
||||
|
||||
Default: true
|
||||
*/
|
||||
Silenced *bool
|
||||
/*Unprocessed
|
||||
Show unprocessed alerts
|
||||
|
||||
/* Unprocessed.
|
||||
|
||||
Show unprocessed alerts
|
||||
|
||||
Default: true
|
||||
*/
|
||||
Unprocessed *bool
|
||||
|
||||
@@ -148,6 +125,41 @@ type GetAlertsParams struct {
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the get alerts params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetAlertsParams) WithDefaults() *GetAlertsParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the get alerts params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetAlertsParams) SetDefaults() {
|
||||
var (
|
||||
activeDefault = bool(true)
|
||||
|
||||
inhibitedDefault = bool(true)
|
||||
|
||||
silencedDefault = bool(true)
|
||||
|
||||
unprocessedDefault = bool(true)
|
||||
)
|
||||
|
||||
val := GetAlertsParams{
|
||||
Active: &activeDefault,
|
||||
Inhibited: &inhibitedDefault,
|
||||
Silenced: &silencedDefault,
|
||||
Unprocessed: &unprocessedDefault,
|
||||
}
|
||||
|
||||
val.timeout = o.timeout
|
||||
val.Context = o.Context
|
||||
val.HTTPClient = o.HTTPClient
|
||||
*o = val
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the get alerts params
|
||||
func (o *GetAlertsParams) WithTimeout(timeout time.Duration) *GetAlertsParams {
|
||||
o.SetTimeout(timeout)
|
||||
@@ -259,88 +271,96 @@ func (o *GetAlertsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Reg
|
||||
|
||||
// query param active
|
||||
var qrActive bool
|
||||
|
||||
if o.Active != nil {
|
||||
qrActive = *o.Active
|
||||
}
|
||||
qActive := swag.FormatBool(qrActive)
|
||||
if qActive != "" {
|
||||
|
||||
if err := r.SetQueryParam("active", qActive); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
valuesFilter := o.Filter
|
||||
if o.Filter != nil {
|
||||
|
||||
joinedFilter := swag.JoinByFormat(valuesFilter, "multi")
|
||||
// query array param filter
|
||||
if err := r.SetQueryParam("filter", joinedFilter...); err != nil {
|
||||
return err
|
||||
// binding items for filter
|
||||
joinedFilter := o.bindParamFilter(reg)
|
||||
|
||||
// query array param filter
|
||||
if err := r.SetQueryParam("filter", joinedFilter...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if o.Inhibited != nil {
|
||||
|
||||
// query param inhibited
|
||||
var qrInhibited bool
|
||||
|
||||
if o.Inhibited != nil {
|
||||
qrInhibited = *o.Inhibited
|
||||
}
|
||||
qInhibited := swag.FormatBool(qrInhibited)
|
||||
if qInhibited != "" {
|
||||
|
||||
if err := r.SetQueryParam("inhibited", qInhibited); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if o.Receiver != nil {
|
||||
|
||||
// query param receiver
|
||||
var qrReceiver string
|
||||
|
||||
if o.Receiver != nil {
|
||||
qrReceiver = *o.Receiver
|
||||
}
|
||||
qReceiver := qrReceiver
|
||||
if qReceiver != "" {
|
||||
|
||||
if err := r.SetQueryParam("receiver", qReceiver); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if o.Silenced != nil {
|
||||
|
||||
// query param silenced
|
||||
var qrSilenced bool
|
||||
|
||||
if o.Silenced != nil {
|
||||
qrSilenced = *o.Silenced
|
||||
}
|
||||
qSilenced := swag.FormatBool(qrSilenced)
|
||||
if qSilenced != "" {
|
||||
|
||||
if err := r.SetQueryParam("silenced", qSilenced); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if o.Unprocessed != nil {
|
||||
|
||||
// query param unprocessed
|
||||
var qrUnprocessed bool
|
||||
|
||||
if o.Unprocessed != nil {
|
||||
qrUnprocessed = *o.Unprocessed
|
||||
}
|
||||
qUnprocessed := swag.FormatBool(qrUnprocessed)
|
||||
if qUnprocessed != "" {
|
||||
|
||||
if err := r.SetQueryParam("unprocessed", qUnprocessed); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
@@ -348,3 +368,20 @@ func (o *GetAlertsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Reg
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindParamGetAlerts binds the parameter filter
|
||||
func (o *GetAlertsParams) bindParamFilter(formats strfmt.Registry) []string {
|
||||
filterIR := o.Filter
|
||||
|
||||
var filterIC []string
|
||||
for _, filterIIR := range filterIR { // explode []string
|
||||
|
||||
filterIIV := filterIIR // string as string
|
||||
filterIC = append(filterIC, filterIIV)
|
||||
}
|
||||
|
||||
// items.CollectionFormat: "multi"
|
||||
filterIS := swag.JoinByFormat(filterIC, "multi")
|
||||
|
||||
return filterIS
|
||||
}
|
||||
|
||||
104
vendor/github.com/prometheus/alertmanager/api/v2/client/alert/get_alerts_responses.go
generated
vendored
104
vendor/github.com/prometheus/alertmanager/api/v2/client/alert/get_alerts_responses.go
generated
vendored
@@ -24,10 +24,9 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
models "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/api/v2/models"
|
||||
)
|
||||
|
||||
// GetAlertsReader is a Reader for the GetAlerts structure.
|
||||
@@ -56,9 +55,8 @@ func (o *GetAlertsReader) ReadResponse(response runtime.ClientResponse, consumer
|
||||
return nil, err
|
||||
}
|
||||
return nil, result
|
||||
|
||||
default:
|
||||
return nil, runtime.NewAPIError("unknown error", response, response.Code())
|
||||
return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +65,8 @@ func NewGetAlertsOK() *GetAlertsOK {
|
||||
return &GetAlertsOK{}
|
||||
}
|
||||
|
||||
/*GetAlertsOK handles this case with default header values.
|
||||
/*
|
||||
GetAlertsOK describes a response with status code 200, with default header values.
|
||||
|
||||
Get alerts response
|
||||
*/
|
||||
@@ -75,10 +74,39 @@ type GetAlertsOK struct {
|
||||
Payload models.GettableAlerts
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get alerts o k response has a 2xx status code
|
||||
func (o *GetAlertsOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get alerts o k response has a 3xx status code
|
||||
func (o *GetAlertsOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get alerts o k response has a 4xx status code
|
||||
func (o *GetAlertsOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get alerts o k response has a 5xx status code
|
||||
func (o *GetAlertsOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this get alerts o k response a status code equal to that given
|
||||
func (o *GetAlertsOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
func (o *GetAlertsOK) Error() string {
|
||||
return fmt.Sprintf("[GET /alerts][%d] getAlertsOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertsOK) String() string {
|
||||
return fmt.Sprintf("[GET /alerts][%d] getAlertsOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertsOK) GetPayload() models.GettableAlerts {
|
||||
return o.Payload
|
||||
}
|
||||
@@ -98,7 +126,8 @@ func NewGetAlertsBadRequest() *GetAlertsBadRequest {
|
||||
return &GetAlertsBadRequest{}
|
||||
}
|
||||
|
||||
/*GetAlertsBadRequest handles this case with default header values.
|
||||
/*
|
||||
GetAlertsBadRequest describes a response with status code 400, with default header values.
|
||||
|
||||
Bad request
|
||||
*/
|
||||
@@ -106,10 +135,39 @@ type GetAlertsBadRequest struct {
|
||||
Payload string
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get alerts bad request response has a 2xx status code
|
||||
func (o *GetAlertsBadRequest) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get alerts bad request response has a 3xx status code
|
||||
func (o *GetAlertsBadRequest) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get alerts bad request response has a 4xx status code
|
||||
func (o *GetAlertsBadRequest) IsClientError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get alerts bad request response has a 5xx status code
|
||||
func (o *GetAlertsBadRequest) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this get alerts bad request response a status code equal to that given
|
||||
func (o *GetAlertsBadRequest) IsCode(code int) bool {
|
||||
return code == 400
|
||||
}
|
||||
|
||||
func (o *GetAlertsBadRequest) Error() string {
|
||||
return fmt.Sprintf("[GET /alerts][%d] getAlertsBadRequest %+v", 400, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertsBadRequest) String() string {
|
||||
return fmt.Sprintf("[GET /alerts][%d] getAlertsBadRequest %+v", 400, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertsBadRequest) GetPayload() string {
|
||||
return o.Payload
|
||||
}
|
||||
@@ -129,7 +187,8 @@ func NewGetAlertsInternalServerError() *GetAlertsInternalServerError {
|
||||
return &GetAlertsInternalServerError{}
|
||||
}
|
||||
|
||||
/*GetAlertsInternalServerError handles this case with default header values.
|
||||
/*
|
||||
GetAlertsInternalServerError describes a response with status code 500, with default header values.
|
||||
|
||||
Internal server error
|
||||
*/
|
||||
@@ -137,10 +196,39 @@ type GetAlertsInternalServerError struct {
|
||||
Payload string
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get alerts internal server error response has a 2xx status code
|
||||
func (o *GetAlertsInternalServerError) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get alerts internal server error response has a 3xx status code
|
||||
func (o *GetAlertsInternalServerError) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get alerts internal server error response has a 4xx status code
|
||||
func (o *GetAlertsInternalServerError) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get alerts internal server error response has a 5xx status code
|
||||
func (o *GetAlertsInternalServerError) IsServerError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsCode returns true when this get alerts internal server error response a status code equal to that given
|
||||
func (o *GetAlertsInternalServerError) IsCode(code int) bool {
|
||||
return code == 500
|
||||
}
|
||||
|
||||
func (o *GetAlertsInternalServerError) Error() string {
|
||||
return fmt.Sprintf("[GET /alerts][%d] getAlertsInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertsInternalServerError) String() string {
|
||||
return fmt.Sprintf("[GET /alerts][%d] getAlertsInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertsInternalServerError) GetPayload() string {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
54
vendor/github.com/prometheus/alertmanager/api/v2/client/alert/post_alerts_parameters.go
generated
vendored
54
vendor/github.com/prometheus/alertmanager/api/v2/client/alert/post_alerts_parameters.go
generated
vendored
@@ -27,59 +27,59 @@ import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
models "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/api/v2/models"
|
||||
)
|
||||
|
||||
// NewPostAlertsParams creates a new PostAlertsParams object
|
||||
// with the default values initialized.
|
||||
// NewPostAlertsParams creates a new PostAlertsParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewPostAlertsParams() *PostAlertsParams {
|
||||
var ()
|
||||
return &PostAlertsParams{
|
||||
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPostAlertsParamsWithTimeout creates a new PostAlertsParams object
|
||||
// with the default values initialized, and the ability to set a timeout on a request
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewPostAlertsParamsWithTimeout(timeout time.Duration) *PostAlertsParams {
|
||||
var ()
|
||||
return &PostAlertsParams{
|
||||
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPostAlertsParamsWithContext creates a new PostAlertsParams object
|
||||
// with the default values initialized, and the ability to set a context for a request
|
||||
// with the ability to set a context for a request.
|
||||
func NewPostAlertsParamsWithContext(ctx context.Context) *PostAlertsParams {
|
||||
var ()
|
||||
return &PostAlertsParams{
|
||||
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPostAlertsParamsWithHTTPClient creates a new PostAlertsParams object
|
||||
// with the default values initialized, and the ability to set a custom HTTPClient for a request
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewPostAlertsParamsWithHTTPClient(client *http.Client) *PostAlertsParams {
|
||||
var ()
|
||||
return &PostAlertsParams{
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*PostAlertsParams contains all the parameters to send to the API endpoint
|
||||
for the post alerts operation typically these are written to a http.Request
|
||||
/*
|
||||
PostAlertsParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the post alerts operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type PostAlertsParams struct {
|
||||
|
||||
/*Alerts
|
||||
The alerts to create
|
||||
/* Alerts.
|
||||
|
||||
The alerts to create
|
||||
*/
|
||||
Alerts models.PostableAlerts
|
||||
|
||||
@@ -88,6 +88,21 @@ type PostAlertsParams struct {
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the post alerts params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *PostAlertsParams) WithDefaults() *PostAlertsParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the post alerts params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *PostAlertsParams) SetDefaults() {
|
||||
// no default values defined for this parameter
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the post alerts params
|
||||
func (o *PostAlertsParams) WithTimeout(timeout time.Duration) *PostAlertsParams {
|
||||
o.SetTimeout(timeout)
|
||||
@@ -139,7 +154,6 @@ func (o *PostAlertsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Re
|
||||
return err
|
||||
}
|
||||
var res []error
|
||||
|
||||
if o.Alerts != nil {
|
||||
if err := r.SetBodyParam(o.Alerts); err != nil {
|
||||
return err
|
||||
|
||||
102
vendor/github.com/prometheus/alertmanager/api/v2/client/alert/post_alerts_responses.go
generated
vendored
102
vendor/github.com/prometheus/alertmanager/api/v2/client/alert/post_alerts_responses.go
generated
vendored
@@ -24,8 +24,7 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// PostAlertsReader is a Reader for the PostAlerts structure.
|
||||
@@ -54,9 +53,8 @@ func (o *PostAlertsReader) ReadResponse(response runtime.ClientResponse, consume
|
||||
return nil, err
|
||||
}
|
||||
return nil, result
|
||||
|
||||
default:
|
||||
return nil, runtime.NewAPIError("unknown error", response, response.Code())
|
||||
return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,17 +63,47 @@ func NewPostAlertsOK() *PostAlertsOK {
|
||||
return &PostAlertsOK{}
|
||||
}
|
||||
|
||||
/*PostAlertsOK handles this case with default header values.
|
||||
/*
|
||||
PostAlertsOK describes a response with status code 200, with default header values.
|
||||
|
||||
Create alerts response
|
||||
*/
|
||||
type PostAlertsOK struct {
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this post alerts o k response has a 2xx status code
|
||||
func (o *PostAlertsOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this post alerts o k response has a 3xx status code
|
||||
func (o *PostAlertsOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this post alerts o k response has a 4xx status code
|
||||
func (o *PostAlertsOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this post alerts o k response has a 5xx status code
|
||||
func (o *PostAlertsOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this post alerts o k response a status code equal to that given
|
||||
func (o *PostAlertsOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
func (o *PostAlertsOK) Error() string {
|
||||
return fmt.Sprintf("[POST /alerts][%d] postAlertsOK ", 200)
|
||||
}
|
||||
|
||||
func (o *PostAlertsOK) String() string {
|
||||
return fmt.Sprintf("[POST /alerts][%d] postAlertsOK ", 200)
|
||||
}
|
||||
|
||||
func (o *PostAlertsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||
|
||||
return nil
|
||||
@@ -86,7 +114,8 @@ func NewPostAlertsBadRequest() *PostAlertsBadRequest {
|
||||
return &PostAlertsBadRequest{}
|
||||
}
|
||||
|
||||
/*PostAlertsBadRequest handles this case with default header values.
|
||||
/*
|
||||
PostAlertsBadRequest describes a response with status code 400, with default header values.
|
||||
|
||||
Bad request
|
||||
*/
|
||||
@@ -94,10 +123,39 @@ type PostAlertsBadRequest struct {
|
||||
Payload string
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this post alerts bad request response has a 2xx status code
|
||||
func (o *PostAlertsBadRequest) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this post alerts bad request response has a 3xx status code
|
||||
func (o *PostAlertsBadRequest) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this post alerts bad request response has a 4xx status code
|
||||
func (o *PostAlertsBadRequest) IsClientError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsServerError returns true when this post alerts bad request response has a 5xx status code
|
||||
func (o *PostAlertsBadRequest) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this post alerts bad request response a status code equal to that given
|
||||
func (o *PostAlertsBadRequest) IsCode(code int) bool {
|
||||
return code == 400
|
||||
}
|
||||
|
||||
func (o *PostAlertsBadRequest) Error() string {
|
||||
return fmt.Sprintf("[POST /alerts][%d] postAlertsBadRequest %+v", 400, o.Payload)
|
||||
}
|
||||
|
||||
func (o *PostAlertsBadRequest) String() string {
|
||||
return fmt.Sprintf("[POST /alerts][%d] postAlertsBadRequest %+v", 400, o.Payload)
|
||||
}
|
||||
|
||||
func (o *PostAlertsBadRequest) GetPayload() string {
|
||||
return o.Payload
|
||||
}
|
||||
@@ -117,7 +175,8 @@ func NewPostAlertsInternalServerError() *PostAlertsInternalServerError {
|
||||
return &PostAlertsInternalServerError{}
|
||||
}
|
||||
|
||||
/*PostAlertsInternalServerError handles this case with default header values.
|
||||
/*
|
||||
PostAlertsInternalServerError describes a response with status code 500, with default header values.
|
||||
|
||||
Internal server error
|
||||
*/
|
||||
@@ -125,10 +184,39 @@ type PostAlertsInternalServerError struct {
|
||||
Payload string
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this post alerts internal server error response has a 2xx status code
|
||||
func (o *PostAlertsInternalServerError) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this post alerts internal server error response has a 3xx status code
|
||||
func (o *PostAlertsInternalServerError) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this post alerts internal server error response has a 4xx status code
|
||||
func (o *PostAlertsInternalServerError) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this post alerts internal server error response has a 5xx status code
|
||||
func (o *PostAlertsInternalServerError) IsServerError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsCode returns true when this post alerts internal server error response a status code equal to that given
|
||||
func (o *PostAlertsInternalServerError) IsCode(code int) bool {
|
||||
return code == 500
|
||||
}
|
||||
|
||||
func (o *PostAlertsInternalServerError) Error() string {
|
||||
return fmt.Sprintf("[POST /alerts][%d] postAlertsInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *PostAlertsInternalServerError) String() string {
|
||||
return fmt.Sprintf("[POST /alerts][%d] postAlertsInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *PostAlertsInternalServerError) GetPayload() string {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
27
vendor/github.com/prometheus/alertmanager/api/v2/client/alertgroup/alertgroup_client.go
generated
vendored
27
vendor/github.com/prometheus/alertmanager/api/v2/client/alertgroup/alertgroup_client.go
generated
vendored
@@ -23,12 +23,11 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// New creates a new alertgroup API client.
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) *Client {
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService {
|
||||
return &Client{transport: transport, formats: formats}
|
||||
}
|
||||
|
||||
@@ -40,16 +39,25 @@ type Client struct {
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// ClientOption is the option for Client methods
|
||||
type ClientOption func(*runtime.ClientOperation)
|
||||
|
||||
// ClientService is the interface for Client methods
|
||||
type ClientService interface {
|
||||
GetAlertGroups(params *GetAlertGroupsParams, opts ...ClientOption) (*GetAlertGroupsOK, error)
|
||||
|
||||
SetTransport(transport runtime.ClientTransport)
|
||||
}
|
||||
|
||||
/*
|
||||
GetAlertGroups Get a list of alert groups
|
||||
*/
|
||||
func (a *Client) GetAlertGroups(params *GetAlertGroupsParams) (*GetAlertGroupsOK, error) {
|
||||
func (a *Client) GetAlertGroups(params *GetAlertGroupsParams, opts ...ClientOption) (*GetAlertGroupsOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewGetAlertGroupsParams()
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(&runtime.ClientOperation{
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "getAlertGroups",
|
||||
Method: "GET",
|
||||
PathPattern: "/alerts/groups",
|
||||
@@ -60,7 +68,12 @@ func (a *Client) GetAlertGroups(params *GetAlertGroupsParams) (*GetAlertGroupsOK
|
||||
Reader: &GetAlertGroupsReader{formats: a.formats},
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
})
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -27,106 +27,88 @@ import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// NewGetAlertGroupsParams creates a new GetAlertGroupsParams object
|
||||
// with the default values initialized.
|
||||
// NewGetAlertGroupsParams creates a new GetAlertGroupsParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewGetAlertGroupsParams() *GetAlertGroupsParams {
|
||||
var (
|
||||
activeDefault = bool(true)
|
||||
inhibitedDefault = bool(true)
|
||||
silencedDefault = bool(true)
|
||||
)
|
||||
return &GetAlertGroupsParams{
|
||||
Active: &activeDefault,
|
||||
Inhibited: &inhibitedDefault,
|
||||
Silenced: &silencedDefault,
|
||||
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetAlertGroupsParamsWithTimeout creates a new GetAlertGroupsParams object
|
||||
// with the default values initialized, and the ability to set a timeout on a request
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewGetAlertGroupsParamsWithTimeout(timeout time.Duration) *GetAlertGroupsParams {
|
||||
var (
|
||||
activeDefault = bool(true)
|
||||
inhibitedDefault = bool(true)
|
||||
silencedDefault = bool(true)
|
||||
)
|
||||
return &GetAlertGroupsParams{
|
||||
Active: &activeDefault,
|
||||
Inhibited: &inhibitedDefault,
|
||||
Silenced: &silencedDefault,
|
||||
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetAlertGroupsParamsWithContext creates a new GetAlertGroupsParams object
|
||||
// with the default values initialized, and the ability to set a context for a request
|
||||
// with the ability to set a context for a request.
|
||||
func NewGetAlertGroupsParamsWithContext(ctx context.Context) *GetAlertGroupsParams {
|
||||
var (
|
||||
activeDefault = bool(true)
|
||||
inhibitedDefault = bool(true)
|
||||
silencedDefault = bool(true)
|
||||
)
|
||||
return &GetAlertGroupsParams{
|
||||
Active: &activeDefault,
|
||||
Inhibited: &inhibitedDefault,
|
||||
Silenced: &silencedDefault,
|
||||
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetAlertGroupsParamsWithHTTPClient creates a new GetAlertGroupsParams object
|
||||
// with the default values initialized, and the ability to set a custom HTTPClient for a request
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewGetAlertGroupsParamsWithHTTPClient(client *http.Client) *GetAlertGroupsParams {
|
||||
var (
|
||||
activeDefault = bool(true)
|
||||
inhibitedDefault = bool(true)
|
||||
silencedDefault = bool(true)
|
||||
)
|
||||
return &GetAlertGroupsParams{
|
||||
Active: &activeDefault,
|
||||
Inhibited: &inhibitedDefault,
|
||||
Silenced: &silencedDefault,
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*GetAlertGroupsParams contains all the parameters to send to the API endpoint
|
||||
for the get alert groups operation typically these are written to a http.Request
|
||||
/*
|
||||
GetAlertGroupsParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the get alert groups operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type GetAlertGroupsParams struct {
|
||||
|
||||
/*Active
|
||||
Show active alerts
|
||||
/* Active.
|
||||
|
||||
Show active alerts
|
||||
|
||||
Default: true
|
||||
*/
|
||||
Active *bool
|
||||
/*Filter
|
||||
A list of matchers to filter alerts by
|
||||
|
||||
/* Filter.
|
||||
|
||||
A list of matchers to filter alerts by
|
||||
*/
|
||||
Filter []string
|
||||
/*Inhibited
|
||||
Show inhibited alerts
|
||||
|
||||
/* Inhibited.
|
||||
|
||||
Show inhibited alerts
|
||||
|
||||
Default: true
|
||||
*/
|
||||
Inhibited *bool
|
||||
/*Receiver
|
||||
A regex matching receivers to filter alerts by
|
||||
|
||||
/* Receiver.
|
||||
|
||||
A regex matching receivers to filter alerts by
|
||||
*/
|
||||
Receiver *string
|
||||
/*Silenced
|
||||
Show silenced alerts
|
||||
|
||||
/* Silenced.
|
||||
|
||||
Show silenced alerts
|
||||
|
||||
Default: true
|
||||
*/
|
||||
Silenced *bool
|
||||
|
||||
@@ -135,6 +117,38 @@ type GetAlertGroupsParams struct {
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the get alert groups params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetAlertGroupsParams) WithDefaults() *GetAlertGroupsParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the get alert groups params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetAlertGroupsParams) SetDefaults() {
|
||||
var (
|
||||
activeDefault = bool(true)
|
||||
|
||||
inhibitedDefault = bool(true)
|
||||
|
||||
silencedDefault = bool(true)
|
||||
)
|
||||
|
||||
val := GetAlertGroupsParams{
|
||||
Active: &activeDefault,
|
||||
Inhibited: &inhibitedDefault,
|
||||
Silenced: &silencedDefault,
|
||||
}
|
||||
|
||||
val.timeout = o.timeout
|
||||
val.Context = o.Context
|
||||
val.HTTPClient = o.HTTPClient
|
||||
*o = val
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the get alert groups params
|
||||
func (o *GetAlertGroupsParams) WithTimeout(timeout time.Duration) *GetAlertGroupsParams {
|
||||
o.SetTimeout(timeout)
|
||||
@@ -235,72 +249,79 @@ func (o *GetAlertGroupsParams) WriteToRequest(r runtime.ClientRequest, reg strfm
|
||||
|
||||
// query param active
|
||||
var qrActive bool
|
||||
|
||||
if o.Active != nil {
|
||||
qrActive = *o.Active
|
||||
}
|
||||
qActive := swag.FormatBool(qrActive)
|
||||
if qActive != "" {
|
||||
|
||||
if err := r.SetQueryParam("active", qActive); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
valuesFilter := o.Filter
|
||||
if o.Filter != nil {
|
||||
|
||||
joinedFilter := swag.JoinByFormat(valuesFilter, "multi")
|
||||
// query array param filter
|
||||
if err := r.SetQueryParam("filter", joinedFilter...); err != nil {
|
||||
return err
|
||||
// binding items for filter
|
||||
joinedFilter := o.bindParamFilter(reg)
|
||||
|
||||
// query array param filter
|
||||
if err := r.SetQueryParam("filter", joinedFilter...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if o.Inhibited != nil {
|
||||
|
||||
// query param inhibited
|
||||
var qrInhibited bool
|
||||
|
||||
if o.Inhibited != nil {
|
||||
qrInhibited = *o.Inhibited
|
||||
}
|
||||
qInhibited := swag.FormatBool(qrInhibited)
|
||||
if qInhibited != "" {
|
||||
|
||||
if err := r.SetQueryParam("inhibited", qInhibited); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if o.Receiver != nil {
|
||||
|
||||
// query param receiver
|
||||
var qrReceiver string
|
||||
|
||||
if o.Receiver != nil {
|
||||
qrReceiver = *o.Receiver
|
||||
}
|
||||
qReceiver := qrReceiver
|
||||
if qReceiver != "" {
|
||||
|
||||
if err := r.SetQueryParam("receiver", qReceiver); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if o.Silenced != nil {
|
||||
|
||||
// query param silenced
|
||||
var qrSilenced bool
|
||||
|
||||
if o.Silenced != nil {
|
||||
qrSilenced = *o.Silenced
|
||||
}
|
||||
qSilenced := swag.FormatBool(qrSilenced)
|
||||
if qSilenced != "" {
|
||||
|
||||
if err := r.SetQueryParam("silenced", qSilenced); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
@@ -308,3 +329,20 @@ func (o *GetAlertGroupsParams) WriteToRequest(r runtime.ClientRequest, reg strfm
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindParamGetAlertGroups binds the parameter filter
|
||||
func (o *GetAlertGroupsParams) bindParamFilter(formats strfmt.Registry) []string {
|
||||
filterIR := o.Filter
|
||||
|
||||
var filterIC []string
|
||||
for _, filterIIR := range filterIR { // explode []string
|
||||
|
||||
filterIIV := filterIIR // string as string
|
||||
filterIC = append(filterIC, filterIIV)
|
||||
}
|
||||
|
||||
// items.CollectionFormat: "multi"
|
||||
filterIS := swag.JoinByFormat(filterIC, "multi")
|
||||
|
||||
return filterIS
|
||||
}
|
||||
|
||||
@@ -24,10 +24,9 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
models "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/api/v2/models"
|
||||
)
|
||||
|
||||
// GetAlertGroupsReader is a Reader for the GetAlertGroups structure.
|
||||
@@ -56,9 +55,8 @@ func (o *GetAlertGroupsReader) ReadResponse(response runtime.ClientResponse, con
|
||||
return nil, err
|
||||
}
|
||||
return nil, result
|
||||
|
||||
default:
|
||||
return nil, runtime.NewAPIError("unknown error", response, response.Code())
|
||||
return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +65,8 @@ func NewGetAlertGroupsOK() *GetAlertGroupsOK {
|
||||
return &GetAlertGroupsOK{}
|
||||
}
|
||||
|
||||
/*GetAlertGroupsOK handles this case with default header values.
|
||||
/*
|
||||
GetAlertGroupsOK describes a response with status code 200, with default header values.
|
||||
|
||||
Get alert groups response
|
||||
*/
|
||||
@@ -75,10 +74,39 @@ type GetAlertGroupsOK struct {
|
||||
Payload models.AlertGroups
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get alert groups o k response has a 2xx status code
|
||||
func (o *GetAlertGroupsOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get alert groups o k response has a 3xx status code
|
||||
func (o *GetAlertGroupsOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get alert groups o k response has a 4xx status code
|
||||
func (o *GetAlertGroupsOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get alert groups o k response has a 5xx status code
|
||||
func (o *GetAlertGroupsOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this get alert groups o k response a status code equal to that given
|
||||
func (o *GetAlertGroupsOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
func (o *GetAlertGroupsOK) Error() string {
|
||||
return fmt.Sprintf("[GET /alerts/groups][%d] getAlertGroupsOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertGroupsOK) String() string {
|
||||
return fmt.Sprintf("[GET /alerts/groups][%d] getAlertGroupsOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertGroupsOK) GetPayload() models.AlertGroups {
|
||||
return o.Payload
|
||||
}
|
||||
@@ -98,7 +126,8 @@ func NewGetAlertGroupsBadRequest() *GetAlertGroupsBadRequest {
|
||||
return &GetAlertGroupsBadRequest{}
|
||||
}
|
||||
|
||||
/*GetAlertGroupsBadRequest handles this case with default header values.
|
||||
/*
|
||||
GetAlertGroupsBadRequest describes a response with status code 400, with default header values.
|
||||
|
||||
Bad request
|
||||
*/
|
||||
@@ -106,10 +135,39 @@ type GetAlertGroupsBadRequest struct {
|
||||
Payload string
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get alert groups bad request response has a 2xx status code
|
||||
func (o *GetAlertGroupsBadRequest) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get alert groups bad request response has a 3xx status code
|
||||
func (o *GetAlertGroupsBadRequest) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get alert groups bad request response has a 4xx status code
|
||||
func (o *GetAlertGroupsBadRequest) IsClientError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get alert groups bad request response has a 5xx status code
|
||||
func (o *GetAlertGroupsBadRequest) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this get alert groups bad request response a status code equal to that given
|
||||
func (o *GetAlertGroupsBadRequest) IsCode(code int) bool {
|
||||
return code == 400
|
||||
}
|
||||
|
||||
func (o *GetAlertGroupsBadRequest) Error() string {
|
||||
return fmt.Sprintf("[GET /alerts/groups][%d] getAlertGroupsBadRequest %+v", 400, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertGroupsBadRequest) String() string {
|
||||
return fmt.Sprintf("[GET /alerts/groups][%d] getAlertGroupsBadRequest %+v", 400, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertGroupsBadRequest) GetPayload() string {
|
||||
return o.Payload
|
||||
}
|
||||
@@ -129,7 +187,8 @@ func NewGetAlertGroupsInternalServerError() *GetAlertGroupsInternalServerError {
|
||||
return &GetAlertGroupsInternalServerError{}
|
||||
}
|
||||
|
||||
/*GetAlertGroupsInternalServerError handles this case with default header values.
|
||||
/*
|
||||
GetAlertGroupsInternalServerError describes a response with status code 500, with default header values.
|
||||
|
||||
Internal server error
|
||||
*/
|
||||
@@ -137,10 +196,39 @@ type GetAlertGroupsInternalServerError struct {
|
||||
Payload string
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get alert groups internal server error response has a 2xx status code
|
||||
func (o *GetAlertGroupsInternalServerError) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get alert groups internal server error response has a 3xx status code
|
||||
func (o *GetAlertGroupsInternalServerError) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get alert groups internal server error response has a 4xx status code
|
||||
func (o *GetAlertGroupsInternalServerError) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get alert groups internal server error response has a 5xx status code
|
||||
func (o *GetAlertGroupsInternalServerError) IsServerError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsCode returns true when this get alert groups internal server error response a status code equal to that given
|
||||
func (o *GetAlertGroupsInternalServerError) IsCode(code int) bool {
|
||||
return code == 500
|
||||
}
|
||||
|
||||
func (o *GetAlertGroupsInternalServerError) Error() string {
|
||||
return fmt.Sprintf("[GET /alerts/groups][%d] getAlertGroupsInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertGroupsInternalServerError) String() string {
|
||||
return fmt.Sprintf("[GET /alerts/groups][%d] getAlertGroupsInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetAlertGroupsInternalServerError) GetPayload() string {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
@@ -22,8 +22,7 @@ package client
|
||||
import (
|
||||
"github.com/go-openapi/runtime"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/prometheus/alertmanager/api/v2/client/alert"
|
||||
"github.com/prometheus/alertmanager/api/v2/client/alertgroup"
|
||||
@@ -32,7 +31,7 @@ import (
|
||||
"github.com/prometheus/alertmanager/api/v2/client/silence"
|
||||
)
|
||||
|
||||
// Default alertmanager HTTP client.
|
||||
// Default alertmanager API HTTP client.
|
||||
var Default = NewHTTPClient(nil)
|
||||
|
||||
const (
|
||||
@@ -41,20 +40,20 @@ const (
|
||||
DefaultHost string = "localhost"
|
||||
// DefaultBasePath is the default BasePath
|
||||
// found in Meta (info) section of spec file
|
||||
DefaultBasePath string = "/"
|
||||
DefaultBasePath string = "/api/v2/"
|
||||
)
|
||||
|
||||
// DefaultSchemes are the default schemes found in Meta (info) section of spec file
|
||||
var DefaultSchemes = []string{"http"}
|
||||
|
||||
// NewHTTPClient creates a new alertmanager HTTP client.
|
||||
func NewHTTPClient(formats strfmt.Registry) *Alertmanager {
|
||||
// NewHTTPClient creates a new alertmanager API HTTP client.
|
||||
func NewHTTPClient(formats strfmt.Registry) *AlertmanagerAPI {
|
||||
return NewHTTPClientWithConfig(formats, nil)
|
||||
}
|
||||
|
||||
// NewHTTPClientWithConfig creates a new alertmanager HTTP client,
|
||||
// NewHTTPClientWithConfig creates a new alertmanager API HTTP client,
|
||||
// using a customizable transport config.
|
||||
func NewHTTPClientWithConfig(formats strfmt.Registry, cfg *TransportConfig) *Alertmanager {
|
||||
func NewHTTPClientWithConfig(formats strfmt.Registry, cfg *TransportConfig) *AlertmanagerAPI {
|
||||
// ensure nullable parameters have default
|
||||
if cfg == nil {
|
||||
cfg = DefaultTransportConfig()
|
||||
@@ -65,26 +64,20 @@ func NewHTTPClientWithConfig(formats strfmt.Registry, cfg *TransportConfig) *Ale
|
||||
return New(transport, formats)
|
||||
}
|
||||
|
||||
// New creates a new alertmanager client
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) *Alertmanager {
|
||||
// New creates a new alertmanager API client
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) *AlertmanagerAPI {
|
||||
// ensure nullable parameters have default
|
||||
if formats == nil {
|
||||
formats = strfmt.Default
|
||||
}
|
||||
|
||||
cli := new(Alertmanager)
|
||||
cli := new(AlertmanagerAPI)
|
||||
cli.Transport = transport
|
||||
|
||||
cli.Alert = alert.New(transport, formats)
|
||||
|
||||
cli.Alertgroup = alertgroup.New(transport, formats)
|
||||
|
||||
cli.General = general.New(transport, formats)
|
||||
|
||||
cli.Receiver = receiver.New(transport, formats)
|
||||
|
||||
cli.Silence = silence.New(transport, formats)
|
||||
|
||||
return cli
|
||||
}
|
||||
|
||||
@@ -127,33 +120,27 @@ func (cfg *TransportConfig) WithSchemes(schemes []string) *TransportConfig {
|
||||
return cfg
|
||||
}
|
||||
|
||||
// Alertmanager is a client for alertmanager
|
||||
type Alertmanager struct {
|
||||
Alert *alert.Client
|
||||
// AlertmanagerAPI is a client for alertmanager API
|
||||
type AlertmanagerAPI struct {
|
||||
Alert alert.ClientService
|
||||
|
||||
Alertgroup *alertgroup.Client
|
||||
Alertgroup alertgroup.ClientService
|
||||
|
||||
General *general.Client
|
||||
General general.ClientService
|
||||
|
||||
Receiver *receiver.Client
|
||||
Receiver receiver.ClientService
|
||||
|
||||
Silence *silence.Client
|
||||
Silence silence.ClientService
|
||||
|
||||
Transport runtime.ClientTransport
|
||||
}
|
||||
|
||||
// SetTransport changes the transport on the client and all its subresources
|
||||
func (c *Alertmanager) SetTransport(transport runtime.ClientTransport) {
|
||||
func (c *AlertmanagerAPI) SetTransport(transport runtime.ClientTransport) {
|
||||
c.Transport = transport
|
||||
|
||||
c.Alert.SetTransport(transport)
|
||||
|
||||
c.Alertgroup.SetTransport(transport)
|
||||
|
||||
c.General.SetTransport(transport)
|
||||
|
||||
c.Receiver.SetTransport(transport)
|
||||
|
||||
c.Silence.SetTransport(transport)
|
||||
|
||||
}
|
||||
27
vendor/github.com/prometheus/alertmanager/api/v2/client/general/general_client.go
generated
vendored
27
vendor/github.com/prometheus/alertmanager/api/v2/client/general/general_client.go
generated
vendored
@@ -23,12 +23,11 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// New creates a new general API client.
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) *Client {
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService {
|
||||
return &Client{transport: transport, formats: formats}
|
||||
}
|
||||
|
||||
@@ -40,16 +39,25 @@ type Client struct {
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// ClientOption is the option for Client methods
|
||||
type ClientOption func(*runtime.ClientOperation)
|
||||
|
||||
// ClientService is the interface for Client methods
|
||||
type ClientService interface {
|
||||
GetStatus(params *GetStatusParams, opts ...ClientOption) (*GetStatusOK, error)
|
||||
|
||||
SetTransport(transport runtime.ClientTransport)
|
||||
}
|
||||
|
||||
/*
|
||||
GetStatus Get current status of an Alertmanager instance and its cluster
|
||||
*/
|
||||
func (a *Client) GetStatus(params *GetStatusParams) (*GetStatusOK, error) {
|
||||
func (a *Client) GetStatus(params *GetStatusParams, opts ...ClientOption) (*GetStatusOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewGetStatusParams()
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(&runtime.ClientOperation{
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "getStatus",
|
||||
Method: "GET",
|
||||
PathPattern: "/status",
|
||||
@@ -60,7 +68,12 @@ func (a *Client) GetStatus(params *GetStatusParams) (*GetStatusOK, error) {
|
||||
Reader: &GetStatusReader{formats: a.formats},
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
})
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
47
vendor/github.com/prometheus/alertmanager/api/v2/client/general/get_status_parameters.go
generated
vendored
47
vendor/github.com/prometheus/alertmanager/api/v2/client/general/get_status_parameters.go
generated
vendored
@@ -27,51 +27,51 @@ import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// NewGetStatusParams creates a new GetStatusParams object
|
||||
// with the default values initialized.
|
||||
// NewGetStatusParams creates a new GetStatusParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewGetStatusParams() *GetStatusParams {
|
||||
|
||||
return &GetStatusParams{
|
||||
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetStatusParamsWithTimeout creates a new GetStatusParams object
|
||||
// with the default values initialized, and the ability to set a timeout on a request
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewGetStatusParamsWithTimeout(timeout time.Duration) *GetStatusParams {
|
||||
|
||||
return &GetStatusParams{
|
||||
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetStatusParamsWithContext creates a new GetStatusParams object
|
||||
// with the default values initialized, and the ability to set a context for a request
|
||||
// with the ability to set a context for a request.
|
||||
func NewGetStatusParamsWithContext(ctx context.Context) *GetStatusParams {
|
||||
|
||||
return &GetStatusParams{
|
||||
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetStatusParamsWithHTTPClient creates a new GetStatusParams object
|
||||
// with the default values initialized, and the ability to set a custom HTTPClient for a request
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewGetStatusParamsWithHTTPClient(client *http.Client) *GetStatusParams {
|
||||
|
||||
return &GetStatusParams{
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*GetStatusParams contains all the parameters to send to the API endpoint
|
||||
for the get status operation typically these are written to a http.Request
|
||||
/*
|
||||
GetStatusParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the get status operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type GetStatusParams struct {
|
||||
timeout time.Duration
|
||||
@@ -79,6 +79,21 @@ type GetStatusParams struct {
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the get status params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetStatusParams) WithDefaults() *GetStatusParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the get status params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetStatusParams) SetDefaults() {
|
||||
// no default values defined for this parameter
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the get status params
|
||||
func (o *GetStatusParams) WithTimeout(timeout time.Duration) *GetStatusParams {
|
||||
o.SetTimeout(timeout)
|
||||
|
||||
40
vendor/github.com/prometheus/alertmanager/api/v2/client/general/get_status_responses.go
generated
vendored
40
vendor/github.com/prometheus/alertmanager/api/v2/client/general/get_status_responses.go
generated
vendored
@@ -24,10 +24,9 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
models "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/api/v2/models"
|
||||
)
|
||||
|
||||
// GetStatusReader is a Reader for the GetStatus structure.
|
||||
@@ -44,9 +43,8 @@ func (o *GetStatusReader) ReadResponse(response runtime.ClientResponse, consumer
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
|
||||
default:
|
||||
return nil, runtime.NewAPIError("unknown error", response, response.Code())
|
||||
return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +53,8 @@ func NewGetStatusOK() *GetStatusOK {
|
||||
return &GetStatusOK{}
|
||||
}
|
||||
|
||||
/*GetStatusOK handles this case with default header values.
|
||||
/*
|
||||
GetStatusOK describes a response with status code 200, with default header values.
|
||||
|
||||
Get status response
|
||||
*/
|
||||
@@ -63,10 +62,39 @@ type GetStatusOK struct {
|
||||
Payload *models.AlertmanagerStatus
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get status o k response has a 2xx status code
|
||||
func (o *GetStatusOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get status o k response has a 3xx status code
|
||||
func (o *GetStatusOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get status o k response has a 4xx status code
|
||||
func (o *GetStatusOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get status o k response has a 5xx status code
|
||||
func (o *GetStatusOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this get status o k response a status code equal to that given
|
||||
func (o *GetStatusOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
func (o *GetStatusOK) Error() string {
|
||||
return fmt.Sprintf("[GET /status][%d] getStatusOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetStatusOK) String() string {
|
||||
return fmt.Sprintf("[GET /status][%d] getStatusOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetStatusOK) GetPayload() *models.AlertmanagerStatus {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
@@ -27,51 +27,51 @@ import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// NewGetReceiversParams creates a new GetReceiversParams object
|
||||
// with the default values initialized.
|
||||
// NewGetReceiversParams creates a new GetReceiversParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewGetReceiversParams() *GetReceiversParams {
|
||||
|
||||
return &GetReceiversParams{
|
||||
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetReceiversParamsWithTimeout creates a new GetReceiversParams object
|
||||
// with the default values initialized, and the ability to set a timeout on a request
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewGetReceiversParamsWithTimeout(timeout time.Duration) *GetReceiversParams {
|
||||
|
||||
return &GetReceiversParams{
|
||||
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetReceiversParamsWithContext creates a new GetReceiversParams object
|
||||
// with the default values initialized, and the ability to set a context for a request
|
||||
// with the ability to set a context for a request.
|
||||
func NewGetReceiversParamsWithContext(ctx context.Context) *GetReceiversParams {
|
||||
|
||||
return &GetReceiversParams{
|
||||
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetReceiversParamsWithHTTPClient creates a new GetReceiversParams object
|
||||
// with the default values initialized, and the ability to set a custom HTTPClient for a request
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewGetReceiversParamsWithHTTPClient(client *http.Client) *GetReceiversParams {
|
||||
|
||||
return &GetReceiversParams{
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*GetReceiversParams contains all the parameters to send to the API endpoint
|
||||
for the get receivers operation typically these are written to a http.Request
|
||||
/*
|
||||
GetReceiversParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the get receivers operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type GetReceiversParams struct {
|
||||
timeout time.Duration
|
||||
@@ -79,6 +79,21 @@ type GetReceiversParams struct {
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the get receivers params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetReceiversParams) WithDefaults() *GetReceiversParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the get receivers params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetReceiversParams) SetDefaults() {
|
||||
// no default values defined for this parameter
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the get receivers params
|
||||
func (o *GetReceiversParams) WithTimeout(timeout time.Duration) *GetReceiversParams {
|
||||
o.SetTimeout(timeout)
|
||||
|
||||
@@ -24,10 +24,9 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
models "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/api/v2/models"
|
||||
)
|
||||
|
||||
// GetReceiversReader is a Reader for the GetReceivers structure.
|
||||
@@ -44,9 +43,8 @@ func (o *GetReceiversReader) ReadResponse(response runtime.ClientResponse, consu
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
|
||||
default:
|
||||
return nil, runtime.NewAPIError("unknown error", response, response.Code())
|
||||
return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +53,8 @@ func NewGetReceiversOK() *GetReceiversOK {
|
||||
return &GetReceiversOK{}
|
||||
}
|
||||
|
||||
/*GetReceiversOK handles this case with default header values.
|
||||
/*
|
||||
GetReceiversOK describes a response with status code 200, with default header values.
|
||||
|
||||
Get receivers response
|
||||
*/
|
||||
@@ -63,10 +62,39 @@ type GetReceiversOK struct {
|
||||
Payload []*models.Receiver
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get receivers o k response has a 2xx status code
|
||||
func (o *GetReceiversOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get receivers o k response has a 3xx status code
|
||||
func (o *GetReceiversOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get receivers o k response has a 4xx status code
|
||||
func (o *GetReceiversOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get receivers o k response has a 5xx status code
|
||||
func (o *GetReceiversOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this get receivers o k response a status code equal to that given
|
||||
func (o *GetReceiversOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
func (o *GetReceiversOK) Error() string {
|
||||
return fmt.Sprintf("[GET /receivers][%d] getReceiversOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetReceiversOK) String() string {
|
||||
return fmt.Sprintf("[GET /receivers][%d] getReceiversOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetReceiversOK) GetPayload() []*models.Receiver {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
27
vendor/github.com/prometheus/alertmanager/api/v2/client/receiver/receiver_client.go
generated
vendored
27
vendor/github.com/prometheus/alertmanager/api/v2/client/receiver/receiver_client.go
generated
vendored
@@ -23,12 +23,11 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// New creates a new receiver API client.
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) *Client {
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService {
|
||||
return &Client{transport: transport, formats: formats}
|
||||
}
|
||||
|
||||
@@ -40,16 +39,25 @@ type Client struct {
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// ClientOption is the option for Client methods
|
||||
type ClientOption func(*runtime.ClientOperation)
|
||||
|
||||
// ClientService is the interface for Client methods
|
||||
type ClientService interface {
|
||||
GetReceivers(params *GetReceiversParams, opts ...ClientOption) (*GetReceiversOK, error)
|
||||
|
||||
SetTransport(transport runtime.ClientTransport)
|
||||
}
|
||||
|
||||
/*
|
||||
GetReceivers Get list of all receivers (name of notification integrations)
|
||||
*/
|
||||
func (a *Client) GetReceivers(params *GetReceiversParams) (*GetReceiversOK, error) {
|
||||
func (a *Client) GetReceivers(params *GetReceiversParams, opts ...ClientOption) (*GetReceiversOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewGetReceiversParams()
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(&runtime.ClientOperation{
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "getReceivers",
|
||||
Method: "GET",
|
||||
PathPattern: "/receivers",
|
||||
@@ -60,7 +68,12 @@ func (a *Client) GetReceivers(params *GetReceiversParams) (*GetReceiversOK, erro
|
||||
Reader: &GetReceiversReader{formats: a.formats},
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
})
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -27,57 +27,59 @@ import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// NewDeleteSilenceParams creates a new DeleteSilenceParams object
|
||||
// with the default values initialized.
|
||||
// NewDeleteSilenceParams creates a new DeleteSilenceParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewDeleteSilenceParams() *DeleteSilenceParams {
|
||||
var ()
|
||||
return &DeleteSilenceParams{
|
||||
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeleteSilenceParamsWithTimeout creates a new DeleteSilenceParams object
|
||||
// with the default values initialized, and the ability to set a timeout on a request
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewDeleteSilenceParamsWithTimeout(timeout time.Duration) *DeleteSilenceParams {
|
||||
var ()
|
||||
return &DeleteSilenceParams{
|
||||
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeleteSilenceParamsWithContext creates a new DeleteSilenceParams object
|
||||
// with the default values initialized, and the ability to set a context for a request
|
||||
// with the ability to set a context for a request.
|
||||
func NewDeleteSilenceParamsWithContext(ctx context.Context) *DeleteSilenceParams {
|
||||
var ()
|
||||
return &DeleteSilenceParams{
|
||||
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeleteSilenceParamsWithHTTPClient creates a new DeleteSilenceParams object
|
||||
// with the default values initialized, and the ability to set a custom HTTPClient for a request
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewDeleteSilenceParamsWithHTTPClient(client *http.Client) *DeleteSilenceParams {
|
||||
var ()
|
||||
return &DeleteSilenceParams{
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*DeleteSilenceParams contains all the parameters to send to the API endpoint
|
||||
for the delete silence operation typically these are written to a http.Request
|
||||
/*
|
||||
DeleteSilenceParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the delete silence operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type DeleteSilenceParams struct {
|
||||
|
||||
/*SilenceID
|
||||
ID of the silence to get
|
||||
/* SilenceID.
|
||||
|
||||
ID of the silence to get
|
||||
|
||||
Format: uuid
|
||||
*/
|
||||
SilenceID strfmt.UUID
|
||||
|
||||
@@ -86,6 +88,21 @@ type DeleteSilenceParams struct {
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the delete silence params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *DeleteSilenceParams) WithDefaults() *DeleteSilenceParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the delete silence params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *DeleteSilenceParams) SetDefaults() {
|
||||
// no default values defined for this parameter
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the delete silence params
|
||||
func (o *DeleteSilenceParams) WithTimeout(timeout time.Duration) *DeleteSilenceParams {
|
||||
o.SetTimeout(timeout)
|
||||
|
||||
@@ -24,8 +24,7 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// DeleteSilenceReader is a Reader for the DeleteSilence structure.
|
||||
@@ -48,9 +47,8 @@ func (o *DeleteSilenceReader) ReadResponse(response runtime.ClientResponse, cons
|
||||
return nil, err
|
||||
}
|
||||
return nil, result
|
||||
|
||||
default:
|
||||
return nil, runtime.NewAPIError("unknown error", response, response.Code())
|
||||
return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,17 +57,47 @@ func NewDeleteSilenceOK() *DeleteSilenceOK {
|
||||
return &DeleteSilenceOK{}
|
||||
}
|
||||
|
||||
/*DeleteSilenceOK handles this case with default header values.
|
||||
/*
|
||||
DeleteSilenceOK describes a response with status code 200, with default header values.
|
||||
|
||||
Delete silence response
|
||||
*/
|
||||
type DeleteSilenceOK struct {
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this delete silence o k response has a 2xx status code
|
||||
func (o *DeleteSilenceOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this delete silence o k response has a 3xx status code
|
||||
func (o *DeleteSilenceOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this delete silence o k response has a 4xx status code
|
||||
func (o *DeleteSilenceOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this delete silence o k response has a 5xx status code
|
||||
func (o *DeleteSilenceOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this delete silence o k response a status code equal to that given
|
||||
func (o *DeleteSilenceOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
func (o *DeleteSilenceOK) Error() string {
|
||||
return fmt.Sprintf("[DELETE /silence/{silenceID}][%d] deleteSilenceOK ", 200)
|
||||
}
|
||||
|
||||
func (o *DeleteSilenceOK) String() string {
|
||||
return fmt.Sprintf("[DELETE /silence/{silenceID}][%d] deleteSilenceOK ", 200)
|
||||
}
|
||||
|
||||
func (o *DeleteSilenceOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||
|
||||
return nil
|
||||
@@ -80,7 +108,8 @@ func NewDeleteSilenceInternalServerError() *DeleteSilenceInternalServerError {
|
||||
return &DeleteSilenceInternalServerError{}
|
||||
}
|
||||
|
||||
/*DeleteSilenceInternalServerError handles this case with default header values.
|
||||
/*
|
||||
DeleteSilenceInternalServerError describes a response with status code 500, with default header values.
|
||||
|
||||
Internal server error
|
||||
*/
|
||||
@@ -88,10 +117,39 @@ type DeleteSilenceInternalServerError struct {
|
||||
Payload string
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this delete silence internal server error response has a 2xx status code
|
||||
func (o *DeleteSilenceInternalServerError) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this delete silence internal server error response has a 3xx status code
|
||||
func (o *DeleteSilenceInternalServerError) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this delete silence internal server error response has a 4xx status code
|
||||
func (o *DeleteSilenceInternalServerError) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this delete silence internal server error response has a 5xx status code
|
||||
func (o *DeleteSilenceInternalServerError) IsServerError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsCode returns true when this delete silence internal server error response a status code equal to that given
|
||||
func (o *DeleteSilenceInternalServerError) IsCode(code int) bool {
|
||||
return code == 500
|
||||
}
|
||||
|
||||
func (o *DeleteSilenceInternalServerError) Error() string {
|
||||
return fmt.Sprintf("[DELETE /silence/{silenceID}][%d] deleteSilenceInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *DeleteSilenceInternalServerError) String() string {
|
||||
return fmt.Sprintf("[DELETE /silence/{silenceID}][%d] deleteSilenceInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *DeleteSilenceInternalServerError) GetPayload() string {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
@@ -27,57 +27,59 @@ import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// NewGetSilenceParams creates a new GetSilenceParams object
|
||||
// with the default values initialized.
|
||||
// NewGetSilenceParams creates a new GetSilenceParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewGetSilenceParams() *GetSilenceParams {
|
||||
var ()
|
||||
return &GetSilenceParams{
|
||||
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetSilenceParamsWithTimeout creates a new GetSilenceParams object
|
||||
// with the default values initialized, and the ability to set a timeout on a request
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewGetSilenceParamsWithTimeout(timeout time.Duration) *GetSilenceParams {
|
||||
var ()
|
||||
return &GetSilenceParams{
|
||||
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetSilenceParamsWithContext creates a new GetSilenceParams object
|
||||
// with the default values initialized, and the ability to set a context for a request
|
||||
// with the ability to set a context for a request.
|
||||
func NewGetSilenceParamsWithContext(ctx context.Context) *GetSilenceParams {
|
||||
var ()
|
||||
return &GetSilenceParams{
|
||||
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetSilenceParamsWithHTTPClient creates a new GetSilenceParams object
|
||||
// with the default values initialized, and the ability to set a custom HTTPClient for a request
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewGetSilenceParamsWithHTTPClient(client *http.Client) *GetSilenceParams {
|
||||
var ()
|
||||
return &GetSilenceParams{
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*GetSilenceParams contains all the parameters to send to the API endpoint
|
||||
for the get silence operation typically these are written to a http.Request
|
||||
/*
|
||||
GetSilenceParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the get silence operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type GetSilenceParams struct {
|
||||
|
||||
/*SilenceID
|
||||
ID of the silence to get
|
||||
/* SilenceID.
|
||||
|
||||
ID of the silence to get
|
||||
|
||||
Format: uuid
|
||||
*/
|
||||
SilenceID strfmt.UUID
|
||||
|
||||
@@ -86,6 +88,21 @@ type GetSilenceParams struct {
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the get silence params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetSilenceParams) WithDefaults() *GetSilenceParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the get silence params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetSilenceParams) SetDefaults() {
|
||||
// no default values defined for this parameter
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the get silence params
|
||||
func (o *GetSilenceParams) WithTimeout(timeout time.Duration) *GetSilenceParams {
|
||||
o.SetTimeout(timeout)
|
||||
|
||||
104
vendor/github.com/prometheus/alertmanager/api/v2/client/silence/get_silence_responses.go
generated
vendored
104
vendor/github.com/prometheus/alertmanager/api/v2/client/silence/get_silence_responses.go
generated
vendored
@@ -24,10 +24,9 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
models "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/api/v2/models"
|
||||
)
|
||||
|
||||
// GetSilenceReader is a Reader for the GetSilence structure.
|
||||
@@ -56,9 +55,8 @@ func (o *GetSilenceReader) ReadResponse(response runtime.ClientResponse, consume
|
||||
return nil, err
|
||||
}
|
||||
return nil, result
|
||||
|
||||
default:
|
||||
return nil, runtime.NewAPIError("unknown error", response, response.Code())
|
||||
return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +65,8 @@ func NewGetSilenceOK() *GetSilenceOK {
|
||||
return &GetSilenceOK{}
|
||||
}
|
||||
|
||||
/*GetSilenceOK handles this case with default header values.
|
||||
/*
|
||||
GetSilenceOK describes a response with status code 200, with default header values.
|
||||
|
||||
Get silence response
|
||||
*/
|
||||
@@ -75,10 +74,39 @@ type GetSilenceOK struct {
|
||||
Payload *models.GettableSilence
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get silence o k response has a 2xx status code
|
||||
func (o *GetSilenceOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get silence o k response has a 3xx status code
|
||||
func (o *GetSilenceOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get silence o k response has a 4xx status code
|
||||
func (o *GetSilenceOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get silence o k response has a 5xx status code
|
||||
func (o *GetSilenceOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this get silence o k response a status code equal to that given
|
||||
func (o *GetSilenceOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
func (o *GetSilenceOK) Error() string {
|
||||
return fmt.Sprintf("[GET /silence/{silenceID}][%d] getSilenceOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetSilenceOK) String() string {
|
||||
return fmt.Sprintf("[GET /silence/{silenceID}][%d] getSilenceOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetSilenceOK) GetPayload() *models.GettableSilence {
|
||||
return o.Payload
|
||||
}
|
||||
@@ -100,17 +128,47 @@ func NewGetSilenceNotFound() *GetSilenceNotFound {
|
||||
return &GetSilenceNotFound{}
|
||||
}
|
||||
|
||||
/*GetSilenceNotFound handles this case with default header values.
|
||||
/*
|
||||
GetSilenceNotFound describes a response with status code 404, with default header values.
|
||||
|
||||
A silence with the specified ID was not found
|
||||
*/
|
||||
type GetSilenceNotFound struct {
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get silence not found response has a 2xx status code
|
||||
func (o *GetSilenceNotFound) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get silence not found response has a 3xx status code
|
||||
func (o *GetSilenceNotFound) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get silence not found response has a 4xx status code
|
||||
func (o *GetSilenceNotFound) IsClientError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get silence not found response has a 5xx status code
|
||||
func (o *GetSilenceNotFound) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this get silence not found response a status code equal to that given
|
||||
func (o *GetSilenceNotFound) IsCode(code int) bool {
|
||||
return code == 404
|
||||
}
|
||||
|
||||
func (o *GetSilenceNotFound) Error() string {
|
||||
return fmt.Sprintf("[GET /silence/{silenceID}][%d] getSilenceNotFound ", 404)
|
||||
}
|
||||
|
||||
func (o *GetSilenceNotFound) String() string {
|
||||
return fmt.Sprintf("[GET /silence/{silenceID}][%d] getSilenceNotFound ", 404)
|
||||
}
|
||||
|
||||
func (o *GetSilenceNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||
|
||||
return nil
|
||||
@@ -121,7 +179,8 @@ func NewGetSilenceInternalServerError() *GetSilenceInternalServerError {
|
||||
return &GetSilenceInternalServerError{}
|
||||
}
|
||||
|
||||
/*GetSilenceInternalServerError handles this case with default header values.
|
||||
/*
|
||||
GetSilenceInternalServerError describes a response with status code 500, with default header values.
|
||||
|
||||
Internal server error
|
||||
*/
|
||||
@@ -129,10 +188,39 @@ type GetSilenceInternalServerError struct {
|
||||
Payload string
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get silence internal server error response has a 2xx status code
|
||||
func (o *GetSilenceInternalServerError) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get silence internal server error response has a 3xx status code
|
||||
func (o *GetSilenceInternalServerError) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get silence internal server error response has a 4xx status code
|
||||
func (o *GetSilenceInternalServerError) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get silence internal server error response has a 5xx status code
|
||||
func (o *GetSilenceInternalServerError) IsServerError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsCode returns true when this get silence internal server error response a status code equal to that given
|
||||
func (o *GetSilenceInternalServerError) IsCode(code int) bool {
|
||||
return code == 500
|
||||
}
|
||||
|
||||
func (o *GetSilenceInternalServerError) Error() string {
|
||||
return fmt.Sprintf("[GET /silence/{silenceID}][%d] getSilenceInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetSilenceInternalServerError) String() string {
|
||||
return fmt.Sprintf("[GET /silence/{silenceID}][%d] getSilenceInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetSilenceInternalServerError) GetPayload() string {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
@@ -27,58 +27,58 @@ import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// NewGetSilencesParams creates a new GetSilencesParams object
|
||||
// with the default values initialized.
|
||||
// NewGetSilencesParams creates a new GetSilencesParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewGetSilencesParams() *GetSilencesParams {
|
||||
var ()
|
||||
return &GetSilencesParams{
|
||||
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetSilencesParamsWithTimeout creates a new GetSilencesParams object
|
||||
// with the default values initialized, and the ability to set a timeout on a request
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewGetSilencesParamsWithTimeout(timeout time.Duration) *GetSilencesParams {
|
||||
var ()
|
||||
return &GetSilencesParams{
|
||||
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetSilencesParamsWithContext creates a new GetSilencesParams object
|
||||
// with the default values initialized, and the ability to set a context for a request
|
||||
// with the ability to set a context for a request.
|
||||
func NewGetSilencesParamsWithContext(ctx context.Context) *GetSilencesParams {
|
||||
var ()
|
||||
return &GetSilencesParams{
|
||||
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetSilencesParamsWithHTTPClient creates a new GetSilencesParams object
|
||||
// with the default values initialized, and the ability to set a custom HTTPClient for a request
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewGetSilencesParamsWithHTTPClient(client *http.Client) *GetSilencesParams {
|
||||
var ()
|
||||
return &GetSilencesParams{
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*GetSilencesParams contains all the parameters to send to the API endpoint
|
||||
for the get silences operation typically these are written to a http.Request
|
||||
/*
|
||||
GetSilencesParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the get silences operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type GetSilencesParams struct {
|
||||
|
||||
/*Filter
|
||||
A list of matchers to filter silences by
|
||||
/* Filter.
|
||||
|
||||
A list of matchers to filter silences by
|
||||
*/
|
||||
Filter []string
|
||||
|
||||
@@ -87,6 +87,21 @@ type GetSilencesParams struct {
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the get silences params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetSilencesParams) WithDefaults() *GetSilencesParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the get silences params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetSilencesParams) SetDefaults() {
|
||||
// no default values defined for this parameter
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the get silences params
|
||||
func (o *GetSilencesParams) WithTimeout(timeout time.Duration) *GetSilencesParams {
|
||||
o.SetTimeout(timeout)
|
||||
@@ -139,12 +154,15 @@ func (o *GetSilencesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.R
|
||||
}
|
||||
var res []error
|
||||
|
||||
valuesFilter := o.Filter
|
||||
if o.Filter != nil {
|
||||
|
||||
joinedFilter := swag.JoinByFormat(valuesFilter, "multi")
|
||||
// query array param filter
|
||||
if err := r.SetQueryParam("filter", joinedFilter...); err != nil {
|
||||
return err
|
||||
// binding items for filter
|
||||
joinedFilter := o.bindParamFilter(reg)
|
||||
|
||||
// query array param filter
|
||||
if err := r.SetQueryParam("filter", joinedFilter...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
@@ -152,3 +170,20 @@ func (o *GetSilencesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.R
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindParamGetSilences binds the parameter filter
|
||||
func (o *GetSilencesParams) bindParamFilter(formats strfmt.Registry) []string {
|
||||
filterIR := o.Filter
|
||||
|
||||
var filterIC []string
|
||||
for _, filterIIR := range filterIR { // explode []string
|
||||
|
||||
filterIIV := filterIIR // string as string
|
||||
filterIC = append(filterIC, filterIIV)
|
||||
}
|
||||
|
||||
// items.CollectionFormat: "multi"
|
||||
filterIS := swag.JoinByFormat(filterIC, "multi")
|
||||
|
||||
return filterIS
|
||||
}
|
||||
|
||||
@@ -24,10 +24,9 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
models "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/api/v2/models"
|
||||
)
|
||||
|
||||
// GetSilencesReader is a Reader for the GetSilences structure.
|
||||
@@ -50,9 +49,8 @@ func (o *GetSilencesReader) ReadResponse(response runtime.ClientResponse, consum
|
||||
return nil, err
|
||||
}
|
||||
return nil, result
|
||||
|
||||
default:
|
||||
return nil, runtime.NewAPIError("unknown error", response, response.Code())
|
||||
return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +59,8 @@ func NewGetSilencesOK() *GetSilencesOK {
|
||||
return &GetSilencesOK{}
|
||||
}
|
||||
|
||||
/*GetSilencesOK handles this case with default header values.
|
||||
/*
|
||||
GetSilencesOK describes a response with status code 200, with default header values.
|
||||
|
||||
Get silences response
|
||||
*/
|
||||
@@ -69,10 +68,39 @@ type GetSilencesOK struct {
|
||||
Payload models.GettableSilences
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get silences o k response has a 2xx status code
|
||||
func (o *GetSilencesOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get silences o k response has a 3xx status code
|
||||
func (o *GetSilencesOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get silences o k response has a 4xx status code
|
||||
func (o *GetSilencesOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get silences o k response has a 5xx status code
|
||||
func (o *GetSilencesOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this get silences o k response a status code equal to that given
|
||||
func (o *GetSilencesOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
func (o *GetSilencesOK) Error() string {
|
||||
return fmt.Sprintf("[GET /silences][%d] getSilencesOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetSilencesOK) String() string {
|
||||
return fmt.Sprintf("[GET /silences][%d] getSilencesOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetSilencesOK) GetPayload() models.GettableSilences {
|
||||
return o.Payload
|
||||
}
|
||||
@@ -92,7 +120,8 @@ func NewGetSilencesInternalServerError() *GetSilencesInternalServerError {
|
||||
return &GetSilencesInternalServerError{}
|
||||
}
|
||||
|
||||
/*GetSilencesInternalServerError handles this case with default header values.
|
||||
/*
|
||||
GetSilencesInternalServerError describes a response with status code 500, with default header values.
|
||||
|
||||
Internal server error
|
||||
*/
|
||||
@@ -100,10 +129,39 @@ type GetSilencesInternalServerError struct {
|
||||
Payload string
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get silences internal server error response has a 2xx status code
|
||||
func (o *GetSilencesInternalServerError) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get silences internal server error response has a 3xx status code
|
||||
func (o *GetSilencesInternalServerError) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get silences internal server error response has a 4xx status code
|
||||
func (o *GetSilencesInternalServerError) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get silences internal server error response has a 5xx status code
|
||||
func (o *GetSilencesInternalServerError) IsServerError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsCode returns true when this get silences internal server error response a status code equal to that given
|
||||
func (o *GetSilencesInternalServerError) IsCode(code int) bool {
|
||||
return code == 500
|
||||
}
|
||||
|
||||
func (o *GetSilencesInternalServerError) Error() string {
|
||||
return fmt.Sprintf("[GET /silences][%d] getSilencesInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetSilencesInternalServerError) String() string {
|
||||
return fmt.Sprintf("[GET /silences][%d] getSilencesInternalServerError %+v", 500, o.Payload)
|
||||
}
|
||||
|
||||
func (o *GetSilencesInternalServerError) GetPayload() string {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
@@ -27,59 +27,59 @@ import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
models "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/api/v2/models"
|
||||
)
|
||||
|
||||
// NewPostSilencesParams creates a new PostSilencesParams object
|
||||
// with the default values initialized.
|
||||
// NewPostSilencesParams creates a new PostSilencesParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewPostSilencesParams() *PostSilencesParams {
|
||||
var ()
|
||||
return &PostSilencesParams{
|
||||
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPostSilencesParamsWithTimeout creates a new PostSilencesParams object
|
||||
// with the default values initialized, and the ability to set a timeout on a request
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewPostSilencesParamsWithTimeout(timeout time.Duration) *PostSilencesParams {
|
||||
var ()
|
||||
return &PostSilencesParams{
|
||||
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPostSilencesParamsWithContext creates a new PostSilencesParams object
|
||||
// with the default values initialized, and the ability to set a context for a request
|
||||
// with the ability to set a context for a request.
|
||||
func NewPostSilencesParamsWithContext(ctx context.Context) *PostSilencesParams {
|
||||
var ()
|
||||
return &PostSilencesParams{
|
||||
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPostSilencesParamsWithHTTPClient creates a new PostSilencesParams object
|
||||
// with the default values initialized, and the ability to set a custom HTTPClient for a request
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewPostSilencesParamsWithHTTPClient(client *http.Client) *PostSilencesParams {
|
||||
var ()
|
||||
return &PostSilencesParams{
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*PostSilencesParams contains all the parameters to send to the API endpoint
|
||||
for the post silences operation typically these are written to a http.Request
|
||||
/*
|
||||
PostSilencesParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the post silences operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type PostSilencesParams struct {
|
||||
|
||||
/*Silence
|
||||
The silence to create
|
||||
/* Silence.
|
||||
|
||||
The silence to create
|
||||
*/
|
||||
Silence *models.PostableSilence
|
||||
|
||||
@@ -88,6 +88,21 @@ type PostSilencesParams struct {
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the post silences params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *PostSilencesParams) WithDefaults() *PostSilencesParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the post silences params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *PostSilencesParams) SetDefaults() {
|
||||
// no default values defined for this parameter
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the post silences params
|
||||
func (o *PostSilencesParams) WithTimeout(timeout time.Duration) *PostSilencesParams {
|
||||
o.SetTimeout(timeout)
|
||||
@@ -139,7 +154,6 @@ func (o *PostSilencesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.
|
||||
return err
|
||||
}
|
||||
var res []error
|
||||
|
||||
if o.Silence != nil {
|
||||
if err := r.SetBodyParam(o.Silence); err != nil {
|
||||
return err
|
||||
|
||||
111
vendor/github.com/prometheus/alertmanager/api/v2/client/silence/post_silences_responses.go
generated
vendored
111
vendor/github.com/prometheus/alertmanager/api/v2/client/silence/post_silences_responses.go
generated
vendored
@@ -20,13 +20,13 @@ package silence
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// PostSilencesReader is a Reader for the PostSilences structure.
|
||||
@@ -55,9 +55,8 @@ func (o *PostSilencesReader) ReadResponse(response runtime.ClientResponse, consu
|
||||
return nil, err
|
||||
}
|
||||
return nil, result
|
||||
|
||||
default:
|
||||
return nil, runtime.NewAPIError("unknown error", response, response.Code())
|
||||
return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +65,8 @@ func NewPostSilencesOK() *PostSilencesOK {
|
||||
return &PostSilencesOK{}
|
||||
}
|
||||
|
||||
/*PostSilencesOK handles this case with default header values.
|
||||
/*
|
||||
PostSilencesOK describes a response with status code 200, with default header values.
|
||||
|
||||
Create / update silence response
|
||||
*/
|
||||
@@ -74,10 +74,39 @@ type PostSilencesOK struct {
|
||||
Payload *PostSilencesOKBody
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this post silences o k response has a 2xx status code
|
||||
func (o *PostSilencesOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this post silences o k response has a 3xx status code
|
||||
func (o *PostSilencesOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this post silences o k response has a 4xx status code
|
||||
func (o *PostSilencesOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this post silences o k response has a 5xx status code
|
||||
func (o *PostSilencesOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this post silences o k response a status code equal to that given
|
||||
func (o *PostSilencesOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
func (o *PostSilencesOK) Error() string {
|
||||
return fmt.Sprintf("[POST /silences][%d] postSilencesOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *PostSilencesOK) String() string {
|
||||
return fmt.Sprintf("[POST /silences][%d] postSilencesOK %+v", 200, o.Payload)
|
||||
}
|
||||
|
||||
func (o *PostSilencesOK) GetPayload() *PostSilencesOKBody {
|
||||
return o.Payload
|
||||
}
|
||||
@@ -99,7 +128,8 @@ func NewPostSilencesBadRequest() *PostSilencesBadRequest {
|
||||
return &PostSilencesBadRequest{}
|
||||
}
|
||||
|
||||
/*PostSilencesBadRequest handles this case with default header values.
|
||||
/*
|
||||
PostSilencesBadRequest describes a response with status code 400, with default header values.
|
||||
|
||||
Bad request
|
||||
*/
|
||||
@@ -107,10 +137,39 @@ type PostSilencesBadRequest struct {
|
||||
Payload string
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this post silences bad request response has a 2xx status code
|
||||
func (o *PostSilencesBadRequest) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this post silences bad request response has a 3xx status code
|
||||
func (o *PostSilencesBadRequest) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this post silences bad request response has a 4xx status code
|
||||
func (o *PostSilencesBadRequest) IsClientError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsServerError returns true when this post silences bad request response has a 5xx status code
|
||||
func (o *PostSilencesBadRequest) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this post silences bad request response a status code equal to that given
|
||||
func (o *PostSilencesBadRequest) IsCode(code int) bool {
|
||||
return code == 400
|
||||
}
|
||||
|
||||
func (o *PostSilencesBadRequest) Error() string {
|
||||
return fmt.Sprintf("[POST /silences][%d] postSilencesBadRequest %+v", 400, o.Payload)
|
||||
}
|
||||
|
||||
func (o *PostSilencesBadRequest) String() string {
|
||||
return fmt.Sprintf("[POST /silences][%d] postSilencesBadRequest %+v", 400, o.Payload)
|
||||
}
|
||||
|
||||
func (o *PostSilencesBadRequest) GetPayload() string {
|
||||
return o.Payload
|
||||
}
|
||||
@@ -130,7 +189,8 @@ func NewPostSilencesNotFound() *PostSilencesNotFound {
|
||||
return &PostSilencesNotFound{}
|
||||
}
|
||||
|
||||
/*PostSilencesNotFound handles this case with default header values.
|
||||
/*
|
||||
PostSilencesNotFound describes a response with status code 404, with default header values.
|
||||
|
||||
A silence with the specified ID was not found
|
||||
*/
|
||||
@@ -138,10 +198,39 @@ type PostSilencesNotFound struct {
|
||||
Payload string
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this post silences not found response has a 2xx status code
|
||||
func (o *PostSilencesNotFound) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this post silences not found response has a 3xx status code
|
||||
func (o *PostSilencesNotFound) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this post silences not found response has a 4xx status code
|
||||
func (o *PostSilencesNotFound) IsClientError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsServerError returns true when this post silences not found response has a 5xx status code
|
||||
func (o *PostSilencesNotFound) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this post silences not found response a status code equal to that given
|
||||
func (o *PostSilencesNotFound) IsCode(code int) bool {
|
||||
return code == 404
|
||||
}
|
||||
|
||||
func (o *PostSilencesNotFound) Error() string {
|
||||
return fmt.Sprintf("[POST /silences][%d] postSilencesNotFound %+v", 404, o.Payload)
|
||||
}
|
||||
|
||||
func (o *PostSilencesNotFound) String() string {
|
||||
return fmt.Sprintf("[POST /silences][%d] postSilencesNotFound %+v", 404, o.Payload)
|
||||
}
|
||||
|
||||
func (o *PostSilencesNotFound) GetPayload() string {
|
||||
return o.Payload
|
||||
}
|
||||
@@ -156,7 +245,8 @@ func (o *PostSilencesNotFound) readResponse(response runtime.ClientResponse, con
|
||||
return nil
|
||||
}
|
||||
|
||||
/*PostSilencesOKBody post silences o k body
|
||||
/*
|
||||
PostSilencesOKBody post silences o k body
|
||||
swagger:model PostSilencesOKBody
|
||||
*/
|
||||
type PostSilencesOKBody struct {
|
||||
@@ -170,6 +260,11 @@ func (o *PostSilencesOKBody) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this post silences o k body based on context it is used
|
||||
func (o *PostSilencesOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (o *PostSilencesOKBody) MarshalBinary() ([]byte, error) {
|
||||
if o == nil {
|
||||
|
||||
69
vendor/github.com/prometheus/alertmanager/api/v2/client/silence/silence_client.go
generated
vendored
69
vendor/github.com/prometheus/alertmanager/api/v2/client/silence/silence_client.go
generated
vendored
@@ -23,12 +23,11 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// New creates a new silence API client.
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) *Client {
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService {
|
||||
return &Client{transport: transport, formats: formats}
|
||||
}
|
||||
|
||||
@@ -40,16 +39,31 @@ type Client struct {
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// ClientOption is the option for Client methods
|
||||
type ClientOption func(*runtime.ClientOperation)
|
||||
|
||||
// ClientService is the interface for Client methods
|
||||
type ClientService interface {
|
||||
DeleteSilence(params *DeleteSilenceParams, opts ...ClientOption) (*DeleteSilenceOK, error)
|
||||
|
||||
GetSilence(params *GetSilenceParams, opts ...ClientOption) (*GetSilenceOK, error)
|
||||
|
||||
GetSilences(params *GetSilencesParams, opts ...ClientOption) (*GetSilencesOK, error)
|
||||
|
||||
PostSilences(params *PostSilencesParams, opts ...ClientOption) (*PostSilencesOK, error)
|
||||
|
||||
SetTransport(transport runtime.ClientTransport)
|
||||
}
|
||||
|
||||
/*
|
||||
DeleteSilence Delete a silence by its ID
|
||||
*/
|
||||
func (a *Client) DeleteSilence(params *DeleteSilenceParams) (*DeleteSilenceOK, error) {
|
||||
func (a *Client) DeleteSilence(params *DeleteSilenceParams, opts ...ClientOption) (*DeleteSilenceOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewDeleteSilenceParams()
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(&runtime.ClientOperation{
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "deleteSilence",
|
||||
Method: "DELETE",
|
||||
PathPattern: "/silence/{silenceID}",
|
||||
@@ -60,7 +74,12 @@ func (a *Client) DeleteSilence(params *DeleteSilenceParams) (*DeleteSilenceOK, e
|
||||
Reader: &DeleteSilenceReader{formats: a.formats},
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
})
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -77,13 +96,12 @@ func (a *Client) DeleteSilence(params *DeleteSilenceParams) (*DeleteSilenceOK, e
|
||||
/*
|
||||
GetSilence Get a silence by its ID
|
||||
*/
|
||||
func (a *Client) GetSilence(params *GetSilenceParams) (*GetSilenceOK, error) {
|
||||
func (a *Client) GetSilence(params *GetSilenceParams, opts ...ClientOption) (*GetSilenceOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewGetSilenceParams()
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(&runtime.ClientOperation{
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "getSilence",
|
||||
Method: "GET",
|
||||
PathPattern: "/silence/{silenceID}",
|
||||
@@ -94,7 +112,12 @@ func (a *Client) GetSilence(params *GetSilenceParams) (*GetSilenceOK, error) {
|
||||
Reader: &GetSilenceReader{formats: a.formats},
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
})
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -111,13 +134,12 @@ func (a *Client) GetSilence(params *GetSilenceParams) (*GetSilenceOK, error) {
|
||||
/*
|
||||
GetSilences Get a list of silences
|
||||
*/
|
||||
func (a *Client) GetSilences(params *GetSilencesParams) (*GetSilencesOK, error) {
|
||||
func (a *Client) GetSilences(params *GetSilencesParams, opts ...ClientOption) (*GetSilencesOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewGetSilencesParams()
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(&runtime.ClientOperation{
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "getSilences",
|
||||
Method: "GET",
|
||||
PathPattern: "/silences",
|
||||
@@ -128,7 +150,12 @@ func (a *Client) GetSilences(params *GetSilencesParams) (*GetSilencesOK, error)
|
||||
Reader: &GetSilencesReader{formats: a.formats},
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
})
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -145,13 +172,12 @@ func (a *Client) GetSilences(params *GetSilencesParams) (*GetSilencesOK, error)
|
||||
/*
|
||||
PostSilences Post a new silence or update an existing one
|
||||
*/
|
||||
func (a *Client) PostSilences(params *PostSilencesParams) (*PostSilencesOK, error) {
|
||||
func (a *Client) PostSilences(params *PostSilencesParams, opts ...ClientOption) (*PostSilencesOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewPostSilencesParams()
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(&runtime.ClientOperation{
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "postSilences",
|
||||
Method: "POST",
|
||||
PathPattern: "/silences",
|
||||
@@ -162,7 +188,12 @@ func (a *Client) PostSilences(params *PostSilencesParams) (*PostSilencesOK, erro
|
||||
Reader: &PostSilencesReader{formats: a.formats},
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
})
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
43
vendor/github.com/prometheus/alertmanager/api/v2/models/alert.go
generated
vendored
43
vendor/github.com/prometheus/alertmanager/api/v2/models/alert.go
generated
vendored
@@ -20,14 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// Alert alert
|
||||
//
|
||||
// swagger:model alert
|
||||
type Alert struct {
|
||||
|
||||
@@ -59,7 +61,6 @@ func (m *Alert) Validate(formats strfmt.Registry) error {
|
||||
}
|
||||
|
||||
func (m *Alert) validateGeneratorURL(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.GeneratorURL) { // not required
|
||||
return nil
|
||||
}
|
||||
@@ -73,9 +74,45 @@ func (m *Alert) validateGeneratorURL(formats strfmt.Registry) error {
|
||||
|
||||
func (m *Alert) validateLabels(formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Labels.Validate(formats); err != nil {
|
||||
if err := validate.Required("labels", "body", m.Labels); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.Labels != nil {
|
||||
if err := m.Labels.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("labels")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("labels")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this alert based on the context it is used
|
||||
func (m *Alert) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateLabels(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Alert) contextValidateLabels(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Labels.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("labels")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("labels")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
97
vendor/github.com/prometheus/alertmanager/api/v2/models/alert_group.go
generated
vendored
97
vendor/github.com/prometheus/alertmanager/api/v2/models/alert_group.go
generated
vendored
@@ -20,16 +20,17 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// AlertGroup alert group
|
||||
//
|
||||
// swagger:model alertGroup
|
||||
type AlertGroup struct {
|
||||
|
||||
@@ -83,6 +84,8 @@ func (m *AlertGroup) validateAlerts(formats strfmt.Registry) error {
|
||||
if err := m.Alerts[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("alerts" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("alerts" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -95,13 +98,21 @@ func (m *AlertGroup) validateAlerts(formats strfmt.Registry) error {
|
||||
|
||||
func (m *AlertGroup) validateLabels(formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Labels.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("labels")
|
||||
}
|
||||
if err := validate.Required("labels", "body", m.Labels); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.Labels != nil {
|
||||
if err := m.Labels.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("labels")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("labels")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -115,6 +126,80 @@ func (m *AlertGroup) validateReceiver(formats strfmt.Registry) error {
|
||||
if err := m.Receiver.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("receiver")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("receiver")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this alert group based on the context it is used
|
||||
func (m *AlertGroup) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateAlerts(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateLabels(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateReceiver(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AlertGroup) contextValidateAlerts(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
for i := 0; i < len(m.Alerts); i++ {
|
||||
|
||||
if m.Alerts[i] != nil {
|
||||
if err := m.Alerts[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("alerts" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("alerts" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AlertGroup) contextValidateLabels(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Labels.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("labels")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("labels")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AlertGroup) contextValidateReceiver(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Receiver != nil {
|
||||
if err := m.Receiver.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("receiver")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("receiver")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
32
vendor/github.com/prometheus/alertmanager/api/v2/models/alert_groups.go
generated
vendored
32
vendor/github.com/prometheus/alertmanager/api/v2/models/alert_groups.go
generated
vendored
@@ -20,15 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// AlertGroups alert groups
|
||||
//
|
||||
// swagger:model alertGroups
|
||||
type AlertGroups []*AlertGroup
|
||||
|
||||
@@ -45,6 +46,33 @@ func (m AlertGroups) Validate(formats strfmt.Registry) error {
|
||||
if err := m[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this alert groups based on the context it is used
|
||||
func (m AlertGroups) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
|
||||
if m[i] != nil {
|
||||
if err := m[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
12
vendor/github.com/prometheus/alertmanager/api/v2/models/alert_status.go
generated
vendored
12
vendor/github.com/prometheus/alertmanager/api/v2/models/alert_status.go
generated
vendored
@@ -20,16 +20,17 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// AlertStatus alert status
|
||||
//
|
||||
// swagger:model alertStatus
|
||||
type AlertStatus struct {
|
||||
|
||||
@@ -113,7 +114,7 @@ const (
|
||||
|
||||
// prop value enum
|
||||
func (m *AlertStatus) validateStateEnum(path, location string, value string) error {
|
||||
if err := validate.Enum(path, location, value, alertStatusTypeStatePropEnum); err != nil {
|
||||
if err := validate.EnumCase(path, location, value, alertStatusTypeStatePropEnum, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -133,6 +134,11 @@ func (m *AlertStatus) validateState(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this alert status based on context it is used
|
||||
func (m *AlertStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AlertStatus) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
9
vendor/github.com/prometheus/alertmanager/api/v2/models/alertmanager_config.go
generated
vendored
9
vendor/github.com/prometheus/alertmanager/api/v2/models/alertmanager_config.go
generated
vendored
@@ -20,14 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// AlertmanagerConfig alertmanager config
|
||||
//
|
||||
// swagger:model alertmanagerConfig
|
||||
type AlertmanagerConfig struct {
|
||||
|
||||
@@ -59,6 +61,11 @@ func (m *AlertmanagerConfig) validateOriginal(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this alertmanager config based on context it is used
|
||||
func (m *AlertmanagerConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AlertmanagerConfig) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
80
vendor/github.com/prometheus/alertmanager/api/v2/models/alertmanager_status.go
generated
vendored
80
vendor/github.com/prometheus/alertmanager/api/v2/models/alertmanager_status.go
generated
vendored
@@ -20,14 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// AlertmanagerStatus alertmanager status
|
||||
//
|
||||
// swagger:model alertmanagerStatus
|
||||
type AlertmanagerStatus struct {
|
||||
|
||||
@@ -85,6 +87,8 @@ func (m *AlertmanagerStatus) validateCluster(formats strfmt.Registry) error {
|
||||
if err := m.Cluster.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("cluster")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("cluster")
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -103,6 +107,8 @@ func (m *AlertmanagerStatus) validateConfig(formats strfmt.Registry) error {
|
||||
if err := m.Config.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("config")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("config")
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -134,6 +140,78 @@ func (m *AlertmanagerStatus) validateVersionInfo(formats strfmt.Registry) error
|
||||
if err := m.VersionInfo.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("versionInfo")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("versionInfo")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this alertmanager status based on the context it is used
|
||||
func (m *AlertmanagerStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateCluster(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateConfig(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateVersionInfo(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AlertmanagerStatus) contextValidateCluster(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Cluster != nil {
|
||||
if err := m.Cluster.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("cluster")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("cluster")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AlertmanagerStatus) contextValidateConfig(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Config != nil {
|
||||
if err := m.Config.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("config")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("config")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AlertmanagerStatus) contextValidateVersionInfo(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.VersionInfo != nil {
|
||||
if err := m.VersionInfo.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("versionInfo")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("versionInfo")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
44
vendor/github.com/prometheus/alertmanager/api/v2/models/cluster_status.go
generated
vendored
44
vendor/github.com/prometheus/alertmanager/api/v2/models/cluster_status.go
generated
vendored
@@ -20,17 +20,18 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// ClusterStatus cluster status
|
||||
//
|
||||
// swagger:model clusterStatus
|
||||
type ClusterStatus struct {
|
||||
|
||||
@@ -65,7 +66,6 @@ func (m *ClusterStatus) Validate(formats strfmt.Registry) error {
|
||||
}
|
||||
|
||||
func (m *ClusterStatus) validatePeers(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Peers) { // not required
|
||||
return nil
|
||||
}
|
||||
@@ -79,6 +79,8 @@ func (m *ClusterStatus) validatePeers(formats strfmt.Registry) error {
|
||||
if err := m.Peers[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("peers" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("peers" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -115,7 +117,7 @@ const (
|
||||
|
||||
// prop value enum
|
||||
func (m *ClusterStatus) validateStatusEnum(path, location string, value string) error {
|
||||
if err := validate.Enum(path, location, value, clusterStatusTypeStatusPropEnum); err != nil {
|
||||
if err := validate.EnumCase(path, location, value, clusterStatusTypeStatusPropEnum, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -135,6 +137,40 @@ func (m *ClusterStatus) validateStatus(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this cluster status based on the context it is used
|
||||
func (m *ClusterStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidatePeers(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ClusterStatus) contextValidatePeers(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
for i := 0; i < len(m.Peers); i++ {
|
||||
|
||||
if m.Peers[i] != nil {
|
||||
if err := m.Peers[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("peers" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("peers" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *ClusterStatus) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
103
vendor/github.com/prometheus/alertmanager/api/v2/models/gettable_alert.go
generated
vendored
103
vendor/github.com/prometheus/alertmanager/api/v2/models/gettable_alert.go
generated
vendored
@@ -20,16 +20,17 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// GettableAlert gettable alert
|
||||
//
|
||||
// swagger:model gettableAlert
|
||||
type GettableAlert struct {
|
||||
|
||||
@@ -158,7 +159,6 @@ func (m GettableAlert) MarshalJSON() ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
_parts = append(_parts, aO1)
|
||||
|
||||
return swag.ConcatJSON(_parts...), nil
|
||||
}
|
||||
|
||||
@@ -207,13 +207,21 @@ func (m *GettableAlert) Validate(formats strfmt.Registry) error {
|
||||
|
||||
func (m *GettableAlert) validateAnnotations(formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Annotations.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("annotations")
|
||||
}
|
||||
if err := validate.Required("annotations", "body", m.Annotations); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.Annotations != nil {
|
||||
if err := m.Annotations.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("annotations")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("annotations")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -254,6 +262,8 @@ func (m *GettableAlert) validateReceivers(formats strfmt.Registry) error {
|
||||
if err := m.Receivers[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("receivers" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("receivers" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -287,6 +297,8 @@ func (m *GettableAlert) validateStatus(formats strfmt.Registry) error {
|
||||
if err := m.Status.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("status")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("status")
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -308,6 +320,83 @@ func (m *GettableAlert) validateUpdatedAt(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this gettable alert based on the context it is used
|
||||
func (m *GettableAlert) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateAnnotations(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateReceivers(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateStatus(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
// validation for a type composition with Alert
|
||||
if err := m.Alert.ContextValidate(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *GettableAlert) contextValidateAnnotations(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Annotations.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("annotations")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("annotations")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *GettableAlert) contextValidateReceivers(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
for i := 0; i < len(m.Receivers); i++ {
|
||||
|
||||
if m.Receivers[i] != nil {
|
||||
if err := m.Receivers[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("receivers" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("receivers" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *GettableAlert) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Status != nil {
|
||||
if err := m.Status.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("status")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("status")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *GettableAlert) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
32
vendor/github.com/prometheus/alertmanager/api/v2/models/gettable_alerts.go
generated
vendored
32
vendor/github.com/prometheus/alertmanager/api/v2/models/gettable_alerts.go
generated
vendored
@@ -20,15 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// GettableAlerts gettable alerts
|
||||
//
|
||||
// swagger:model gettableAlerts
|
||||
type GettableAlerts []*GettableAlert
|
||||
|
||||
@@ -45,6 +46,33 @@ func (m GettableAlerts) Validate(formats strfmt.Registry) error {
|
||||
if err := m[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this gettable alerts based on the context it is used
|
||||
func (m GettableAlerts) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
|
||||
if m[i] != nil {
|
||||
if err := m[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
42
vendor/github.com/prometheus/alertmanager/api/v2/models/gettable_silence.go
generated
vendored
42
vendor/github.com/prometheus/alertmanager/api/v2/models/gettable_silence.go
generated
vendored
@@ -20,14 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// GettableSilence gettable silence
|
||||
//
|
||||
// swagger:model gettableSilence
|
||||
type GettableSilence struct {
|
||||
|
||||
@@ -106,7 +108,6 @@ func (m GettableSilence) MarshalJSON() ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
_parts = append(_parts, aO1)
|
||||
|
||||
return swag.ConcatJSON(_parts...), nil
|
||||
}
|
||||
|
||||
@@ -156,6 +157,8 @@ func (m *GettableSilence) validateStatus(formats strfmt.Registry) error {
|
||||
if err := m.Status.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("status")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("status")
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -177,6 +180,41 @@ func (m *GettableSilence) validateUpdatedAt(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this gettable silence based on the context it is used
|
||||
func (m *GettableSilence) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateStatus(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
// validation for a type composition with Silence
|
||||
if err := m.Silence.ContextValidate(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *GettableSilence) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Status != nil {
|
||||
if err := m.Status.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("status")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("status")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *GettableSilence) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
32
vendor/github.com/prometheus/alertmanager/api/v2/models/gettable_silences.go
generated
vendored
32
vendor/github.com/prometheus/alertmanager/api/v2/models/gettable_silences.go
generated
vendored
@@ -20,15 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// GettableSilences gettable silences
|
||||
//
|
||||
// swagger:model gettableSilences
|
||||
type GettableSilences []*GettableSilence
|
||||
|
||||
@@ -45,6 +46,33 @@ func (m GettableSilences) Validate(formats strfmt.Registry) error {
|
||||
if err := m[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this gettable silences based on the context it is used
|
||||
func (m GettableSilences) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
|
||||
if m[i] != nil {
|
||||
if err := m[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
10
vendor/github.com/prometheus/alertmanager/api/v2/models/label_set.go
generated
vendored
10
vendor/github.com/prometheus/alertmanager/api/v2/models/label_set.go
generated
vendored
@@ -20,10 +20,13 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// LabelSet label set
|
||||
//
|
||||
// swagger:model labelSet
|
||||
type LabelSet map[string]string
|
||||
|
||||
@@ -31,3 +34,8 @@ type LabelSet map[string]string
|
||||
func (m LabelSet) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this label set based on context it is used
|
||||
func (m LabelSet) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
12
vendor/github.com/prometheus/alertmanager/api/v2/models/matcher.go
generated
vendored
12
vendor/github.com/prometheus/alertmanager/api/v2/models/matcher.go
generated
vendored
@@ -20,17 +20,22 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// Matcher matcher
|
||||
//
|
||||
// swagger:model matcher
|
||||
type Matcher struct {
|
||||
|
||||
// is equal
|
||||
IsEqual *bool `json:"isEqual,omitempty"`
|
||||
|
||||
// is regex
|
||||
// Required: true
|
||||
IsRegex *bool `json:"isRegex"`
|
||||
@@ -93,6 +98,11 @@ func (m *Matcher) validateValue(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this matcher based on context it is used
|
||||
func (m *Matcher) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *Matcher) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
32
vendor/github.com/prometheus/alertmanager/api/v2/models/matchers.go
generated
vendored
32
vendor/github.com/prometheus/alertmanager/api/v2/models/matchers.go
generated
vendored
@@ -20,16 +20,17 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// Matchers matchers
|
||||
//
|
||||
// swagger:model matchers
|
||||
type Matchers []*Matcher
|
||||
|
||||
@@ -52,6 +53,33 @@ func (m Matchers) Validate(formats strfmt.Registry) error {
|
||||
if err := m[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this matchers based on the context it is used
|
||||
func (m Matchers) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
|
||||
if m[i] != nil {
|
||||
if err := m[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
9
vendor/github.com/prometheus/alertmanager/api/v2/models/peer_status.go
generated
vendored
9
vendor/github.com/prometheus/alertmanager/api/v2/models/peer_status.go
generated
vendored
@@ -20,14 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// PeerStatus peer status
|
||||
//
|
||||
// swagger:model peerStatus
|
||||
type PeerStatus struct {
|
||||
|
||||
@@ -76,6 +78,11 @@ func (m *PeerStatus) validateName(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this peer status based on context it is used
|
||||
func (m *PeerStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *PeerStatus) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
50
vendor/github.com/prometheus/alertmanager/api/v2/models/postable_alert.go
generated
vendored
50
vendor/github.com/prometheus/alertmanager/api/v2/models/postable_alert.go
generated
vendored
@@ -20,14 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// PostableAlert postable alert
|
||||
//
|
||||
// swagger:model postableAlert
|
||||
type PostableAlert struct {
|
||||
|
||||
@@ -104,7 +106,6 @@ func (m PostableAlert) MarshalJSON() ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
_parts = append(_parts, aO1)
|
||||
|
||||
return swag.ConcatJSON(_parts...), nil
|
||||
}
|
||||
|
||||
@@ -141,11 +142,15 @@ func (m *PostableAlert) validateAnnotations(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.Annotations.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("annotations")
|
||||
if m.Annotations != nil {
|
||||
if err := m.Annotations.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("annotations")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("annotations")
|
||||
}
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -177,6 +182,39 @@ func (m *PostableAlert) validateStartsAt(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this postable alert based on the context it is used
|
||||
func (m *PostableAlert) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateAnnotations(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
// validation for a type composition with Alert
|
||||
if err := m.Alert.ContextValidate(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PostableAlert) contextValidateAnnotations(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Annotations.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("annotations")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("annotations")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *PostableAlert) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
32
vendor/github.com/prometheus/alertmanager/api/v2/models/postable_alerts.go
generated
vendored
32
vendor/github.com/prometheus/alertmanager/api/v2/models/postable_alerts.go
generated
vendored
@@ -20,15 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// PostableAlerts postable alerts
|
||||
//
|
||||
// swagger:model postableAlerts
|
||||
type PostableAlerts []*PostableAlert
|
||||
|
||||
@@ -45,6 +46,33 @@ func (m PostableAlerts) Validate(formats strfmt.Registry) error {
|
||||
if err := m[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this postable alerts based on the context it is used
|
||||
func (m PostableAlerts) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
|
||||
if m[i] != nil {
|
||||
if err := m[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
20
vendor/github.com/prometheus/alertmanager/api/v2/models/postable_silence.go
generated
vendored
20
vendor/github.com/prometheus/alertmanager/api/v2/models/postable_silence.go
generated
vendored
@@ -20,13 +20,15 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// PostableSilence postable silence
|
||||
//
|
||||
// swagger:model postableSilence
|
||||
type PostableSilence struct {
|
||||
|
||||
@@ -79,7 +81,6 @@ func (m PostableSilence) MarshalJSON() ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
_parts = append(_parts, aO1)
|
||||
|
||||
return swag.ConcatJSON(_parts...), nil
|
||||
}
|
||||
|
||||
@@ -98,6 +99,21 @@ func (m *PostableSilence) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this postable silence based on the context it is used
|
||||
func (m *PostableSilence) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
// validation for a type composition with Silence
|
||||
if err := m.Silence.ContextValidate(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *PostableSilence) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
9
vendor/github.com/prometheus/alertmanager/api/v2/models/receiver.go
generated
vendored
9
vendor/github.com/prometheus/alertmanager/api/v2/models/receiver.go
generated
vendored
@@ -20,14 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// Receiver receiver
|
||||
//
|
||||
// swagger:model receiver
|
||||
type Receiver struct {
|
||||
|
||||
@@ -59,6 +61,11 @@ func (m *Receiver) validateName(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this receiver based on context it is used
|
||||
func (m *Receiver) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *Receiver) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
34
vendor/github.com/prometheus/alertmanager/api/v2/models/silence.go
generated
vendored
34
vendor/github.com/prometheus/alertmanager/api/v2/models/silence.go
generated
vendored
@@ -20,14 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// Silence silence
|
||||
//
|
||||
// swagger:model silence
|
||||
type Silence struct {
|
||||
|
||||
@@ -124,6 +126,8 @@ func (m *Silence) validateMatchers(formats strfmt.Registry) error {
|
||||
if err := m.Matchers.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("matchers")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("matchers")
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -144,6 +148,34 @@ func (m *Silence) validateStartsAt(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this silence based on the context it is used
|
||||
func (m *Silence) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateMatchers(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Silence) contextValidateMatchers(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Matchers.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("matchers")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("matchers")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *Silence) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
12
vendor/github.com/prometheus/alertmanager/api/v2/models/silence_status.go
generated
vendored
12
vendor/github.com/prometheus/alertmanager/api/v2/models/silence_status.go
generated
vendored
@@ -20,16 +20,17 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// SilenceStatus silence status
|
||||
//
|
||||
// swagger:model silenceStatus
|
||||
type SilenceStatus struct {
|
||||
|
||||
@@ -79,7 +80,7 @@ const (
|
||||
|
||||
// prop value enum
|
||||
func (m *SilenceStatus) validateStateEnum(path, location string, value string) error {
|
||||
if err := validate.Enum(path, location, value, silenceStatusTypeStatePropEnum); err != nil {
|
||||
if err := validate.EnumCase(path, location, value, silenceStatusTypeStatePropEnum, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -99,6 +100,11 @@ func (m *SilenceStatus) validateState(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this silence status based on context it is used
|
||||
func (m *SilenceStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *SilenceStatus) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
9
vendor/github.com/prometheus/alertmanager/api/v2/models/version_info.go
generated
vendored
9
vendor/github.com/prometheus/alertmanager/api/v2/models/version_info.go
generated
vendored
@@ -20,14 +20,16 @@ package models
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
strfmt "github.com/go-openapi/strfmt"
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/go-openapi/validate"
|
||||
)
|
||||
|
||||
// VersionInfo version info
|
||||
//
|
||||
// swagger:model versionInfo
|
||||
type VersionInfo struct {
|
||||
|
||||
@@ -144,6 +146,11 @@ func (m *VersionInfo) validateVersion(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this version info based on context it is used
|
||||
func (m *VersionInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *VersionInfo) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
||||
115
vendor/github.com/prometheus/alertmanager/pkg/labels/matcher.go
generated
vendored
115
vendor/github.com/prometheus/alertmanager/pkg/labels/matcher.go
generated
vendored
@@ -14,8 +14,13 @@
|
||||
package labels
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
// MatchType is an enum for label matching types.
|
||||
@@ -69,7 +74,7 @@ func NewMatcher(t MatchType, n, v string) (*Matcher, error) {
|
||||
}
|
||||
|
||||
func (m *Matcher) String() string {
|
||||
return fmt.Sprintf("%s%s%q", m.Name, m.Type, m.Value)
|
||||
return fmt.Sprintf(`%s%s"%s"`, m.Name, m.Type, openMetricsEscape(m.Value))
|
||||
}
|
||||
|
||||
// Matches returns whether the matcher matches the given string value.
|
||||
@@ -86,3 +91,111 @@ func (m *Matcher) Matches(s string) bool {
|
||||
}
|
||||
panic("labels.Matcher.Matches: invalid match type")
|
||||
}
|
||||
|
||||
type apiV1Matcher struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
IsRegex bool `json:"isRegex"`
|
||||
IsEqual bool `json:"isEqual"`
|
||||
}
|
||||
|
||||
// MarshalJSON retains backwards compatibility with types.Matcher for the v1 API.
|
||||
func (m Matcher) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(apiV1Matcher{
|
||||
Name: m.Name,
|
||||
Value: m.Value,
|
||||
IsRegex: m.Type == MatchRegexp || m.Type == MatchNotRegexp,
|
||||
IsEqual: m.Type == MatchRegexp || m.Type == MatchEqual,
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Matcher) UnmarshalJSON(data []byte) error {
|
||||
v1m := apiV1Matcher{
|
||||
IsEqual: true,
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &v1m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var t MatchType
|
||||
switch {
|
||||
case v1m.IsEqual && !v1m.IsRegex:
|
||||
t = MatchEqual
|
||||
case !v1m.IsEqual && !v1m.IsRegex:
|
||||
t = MatchNotEqual
|
||||
case v1m.IsEqual && v1m.IsRegex:
|
||||
t = MatchRegexp
|
||||
case !v1m.IsEqual && v1m.IsRegex:
|
||||
t = MatchNotRegexp
|
||||
}
|
||||
|
||||
matcher, err := NewMatcher(t, v1m.Name, v1m.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*m = *matcher
|
||||
return nil
|
||||
}
|
||||
|
||||
// openMetricsEscape is similar to the usual string escaping, but more
|
||||
// restricted. It merely replaces a new-line character with '\n', a double-quote
|
||||
// character with '\"', and a backslash with '\\', which is the escaping used by
|
||||
// OpenMetrics.
|
||||
func openMetricsEscape(s string) string {
|
||||
r := strings.NewReplacer(
|
||||
`\`, `\\`,
|
||||
"\n", `\n`,
|
||||
`"`, `\"`,
|
||||
)
|
||||
return r.Replace(s)
|
||||
}
|
||||
|
||||
// Matchers is a slice of Matchers that is sortable, implements Stringer, and
|
||||
// provides a Matches method to match a LabelSet against all Matchers in the
|
||||
// slice. Note that some users of Matchers might require it to be sorted.
|
||||
type Matchers []*Matcher
|
||||
|
||||
func (ms Matchers) Len() int { return len(ms) }
|
||||
func (ms Matchers) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
|
||||
|
||||
func (ms Matchers) Less(i, j int) bool {
|
||||
if ms[i].Name > ms[j].Name {
|
||||
return false
|
||||
}
|
||||
if ms[i].Name < ms[j].Name {
|
||||
return true
|
||||
}
|
||||
if ms[i].Value > ms[j].Value {
|
||||
return false
|
||||
}
|
||||
if ms[i].Value < ms[j].Value {
|
||||
return true
|
||||
}
|
||||
return ms[i].Type < ms[j].Type
|
||||
}
|
||||
|
||||
// Matches checks whether all matchers are fulfilled against the given label set.
|
||||
func (ms Matchers) Matches(lset model.LabelSet) bool {
|
||||
for _, m := range ms {
|
||||
if !m.Matches(string(lset[model.LabelName(m.Name)])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (ms Matchers) String() string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
buf.WriteByte('{')
|
||||
for i, m := range ms {
|
||||
if i > 0 {
|
||||
buf.WriteByte(',')
|
||||
}
|
||||
buf.WriteString(m.String())
|
||||
}
|
||||
buf.WriteByte('}')
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
149
vendor/github.com/prometheus/alertmanager/pkg/labels/parse.go
generated
vendored
149
vendor/github.com/prometheus/alertmanager/pkg/labels/parse.go
generated
vendored
@@ -16,12 +16,15 @@ package labels
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
re = regexp.MustCompile(`(?:\s?)(\w+)(=|=~|!=|!~)(?:\"([^"=~!]+)\"|([^"=~!]+)|\"\")`)
|
||||
// '=~' has to come before '=' because otherwise only the '='
|
||||
// will be consumed, and the '~' will be part of the 3rd token.
|
||||
re = regexp.MustCompile(`^\s*([a-zA-Z_:][a-zA-Z0-9_:]*)\s*(=~|=|!=|!~)\s*((?s).*?)\s*$`)
|
||||
typeMap = map[string]MatchType{
|
||||
"=": MatchEqual,
|
||||
"!=": MatchNotEqual,
|
||||
@@ -30,27 +33,60 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// ParseMatchers parses a comma-separated list of Matchers. A leading '{' and/or
|
||||
// a trailing '}' is optional and will be trimmed before further
|
||||
// parsing. Individual Matchers are separated by commas outside of quoted parts
|
||||
// of the input string. Those commas may be surrounded by whitespace. Parts of the
|
||||
// string inside unescaped double quotes ('"…"') are considered quoted (and
|
||||
// commas don't act as separators there). If double quotes are escaped with a
|
||||
// single backslash ('\"'), they are ignored for the purpose of identifying
|
||||
// quoted parts of the input string. If the input string, after trimming the
|
||||
// optional trailing '}', ends with a comma, followed by optional whitespace,
|
||||
// this comma and whitespace will be trimmed.
|
||||
//
|
||||
// Examples for valid input strings:
|
||||
//
|
||||
// {foo = "bar", dings != "bums", }
|
||||
// foo=bar,dings!=bums
|
||||
// foo=bar, dings!=bums
|
||||
// {quote="She said: \"Hi, ladies! That's gender-neutral…\""}
|
||||
// statuscode=~"5.."
|
||||
//
|
||||
// See ParseMatcher for details on how an individual Matcher is parsed.
|
||||
func ParseMatchers(s string) ([]*Matcher, error) {
|
||||
matchers := []*Matcher{}
|
||||
s = strings.TrimPrefix(s, "{")
|
||||
s = strings.TrimSuffix(s, "}")
|
||||
|
||||
var insideQuotes bool
|
||||
var token string
|
||||
var tokens []string
|
||||
var (
|
||||
insideQuotes bool
|
||||
escaped bool
|
||||
token strings.Builder
|
||||
tokens []string
|
||||
)
|
||||
for _, r := range s {
|
||||
if !insideQuotes && r == ',' {
|
||||
tokens = append(tokens, token)
|
||||
token = ""
|
||||
continue
|
||||
}
|
||||
token += string(r)
|
||||
if r == '"' {
|
||||
insideQuotes = !insideQuotes
|
||||
switch r {
|
||||
case ',':
|
||||
if !insideQuotes {
|
||||
tokens = append(tokens, token.String())
|
||||
token.Reset()
|
||||
continue
|
||||
}
|
||||
case '"':
|
||||
if !escaped {
|
||||
insideQuotes = !insideQuotes
|
||||
} else {
|
||||
escaped = false
|
||||
}
|
||||
case '\\':
|
||||
escaped = !escaped
|
||||
default:
|
||||
escaped = false
|
||||
}
|
||||
token.WriteRune(r)
|
||||
}
|
||||
if token != "" {
|
||||
tokens = append(tokens, token)
|
||||
if s := strings.TrimSpace(token.String()); s != "" {
|
||||
tokens = append(tokens, s)
|
||||
}
|
||||
for _, token := range tokens {
|
||||
m, err := ParseMatcher(token)
|
||||
@@ -63,32 +99,81 @@ func ParseMatchers(s string) ([]*Matcher, error) {
|
||||
return matchers, nil
|
||||
}
|
||||
|
||||
func ParseMatcher(s string) (*Matcher, error) {
|
||||
var (
|
||||
name, value string
|
||||
matchType MatchType
|
||||
)
|
||||
|
||||
// ParseMatcher parses a matcher with a syntax inspired by PromQL and
|
||||
// OpenMetrics. This syntax is convenient to describe filters and selectors in
|
||||
// UIs and config files. To support the interactive nature of the use cases, the
|
||||
// parser is in various aspects fairly tolerant.
|
||||
//
|
||||
// The syntax of a matcher consists of three tokens: (1) A valid Prometheus
|
||||
// label name. (2) One of '=', '!=', '=~', or '!~', with the same meaning as
|
||||
// known from PromQL selectors. (3) A UTF-8 string, which may be enclosed in
|
||||
// double quotes. Before or after each token, there may be any amount of
|
||||
// whitespace, which will be discarded. The 3rd token may be the empty
|
||||
// string. Within the 3rd token, OpenMetrics escaping rules apply: '\"' for a
|
||||
// double-quote, '\n' for a line feed, '\\' for a literal backslash. Unescaped
|
||||
// '"' must not occur inside the 3rd token (only as the 1st or last
|
||||
// character). However, literal line feed characters are tolerated, as are
|
||||
// single '\' characters not followed by '\', 'n', or '"'. They act as a literal
|
||||
// backslash in that case.
|
||||
func ParseMatcher(s string) (_ *Matcher, err error) {
|
||||
ms := re.FindStringSubmatch(s)
|
||||
if len(ms) < 4 {
|
||||
if len(ms) == 0 {
|
||||
return nil, errors.Errorf("bad matcher format: %s", s)
|
||||
}
|
||||
|
||||
name = ms[1]
|
||||
if name == "" {
|
||||
return nil, errors.New("failed to parse label name")
|
||||
var (
|
||||
rawValue = ms[3]
|
||||
value strings.Builder
|
||||
escaped bool
|
||||
expectTrailingQuote bool
|
||||
)
|
||||
|
||||
if strings.HasPrefix(rawValue, "\"") {
|
||||
rawValue = strings.TrimPrefix(rawValue, "\"")
|
||||
expectTrailingQuote = true
|
||||
}
|
||||
|
||||
matchType, found := typeMap[ms[2]]
|
||||
if !found {
|
||||
return nil, errors.New("failed to find match operator")
|
||||
if !utf8.ValidString(rawValue) {
|
||||
return nil, errors.Errorf("matcher value not valid UTF-8: %s", ms[3])
|
||||
}
|
||||
|
||||
if ms[3] != "" {
|
||||
value = ms[3]
|
||||
} else {
|
||||
value = ms[4]
|
||||
// Unescape the rawValue:
|
||||
for i, r := range rawValue {
|
||||
if escaped {
|
||||
escaped = false
|
||||
switch r {
|
||||
case 'n':
|
||||
value.WriteByte('\n')
|
||||
case '"', '\\':
|
||||
value.WriteRune(r)
|
||||
default:
|
||||
// This was a spurious escape, so treat the '\' as literal.
|
||||
value.WriteByte('\\')
|
||||
value.WriteRune(r)
|
||||
}
|
||||
continue
|
||||
}
|
||||
switch r {
|
||||
case '\\':
|
||||
if i < len(rawValue)-1 {
|
||||
escaped = true
|
||||
continue
|
||||
}
|
||||
// '\' encountered as last byte. Treat it as literal.
|
||||
value.WriteByte('\\')
|
||||
case '"':
|
||||
if !expectTrailingQuote || i < len(rawValue)-1 {
|
||||
return nil, errors.Errorf("matcher value contains unescaped double quote: %s", ms[3])
|
||||
}
|
||||
expectTrailingQuote = false
|
||||
default:
|
||||
value.WriteRune(r)
|
||||
}
|
||||
}
|
||||
|
||||
return NewMatcher(matchType, name, value)
|
||||
if expectTrailingQuote {
|
||||
return nil, errors.Errorf("matcher value contains unescaped double quote: %s", ms[3])
|
||||
}
|
||||
|
||||
return NewMatcher(typeMap[ms[2]], ms[1], value.String())
|
||||
}
|
||||
|
||||
26
vendor/github.com/prometheus/common/config/config.go
generated
vendored
26
vendor/github.com/prometheus/common/config/config.go
generated
vendored
@@ -18,6 +18,7 @@ package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
@@ -34,7 +35,7 @@ func (s Secret) MarshalYAML() (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
//UnmarshalYAML implements the yaml.Unmarshaler interface for Secrets.
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface for Secrets.
|
||||
func (s *Secret) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
type plain Secret
|
||||
return unmarshal((*plain)(s))
|
||||
@@ -48,6 +49,29 @@ func (s Secret) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(secretToken)
|
||||
}
|
||||
|
||||
type Header map[string][]Secret
|
||||
|
||||
func (h *Header) HTTPHeader() http.Header {
|
||||
if h == nil || *h == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
header := make(http.Header)
|
||||
|
||||
for name, values := range *h {
|
||||
var s []string
|
||||
if values != nil {
|
||||
s = make([]string, 0, len(values))
|
||||
for _, value := range values {
|
||||
s = append(s, string(value))
|
||||
}
|
||||
}
|
||||
header[name] = s
|
||||
}
|
||||
|
||||
return header
|
||||
}
|
||||
|
||||
// DirectorySetter is a config type that contains file paths that may
|
||||
// be relative to the file containing the config.
|
||||
type DirectorySetter interface {
|
||||
|
||||
162
vendor/github.com/prometheus/common/config/http_config.go
generated
vendored
162
vendor/github.com/prometheus/common/config/http_config.go
generated
vendored
@@ -21,10 +21,11 @@ import (
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -80,7 +81,7 @@ func (tv *TLSVersion) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
}
|
||||
|
||||
func (tv *TLSVersion) MarshalYAML() (interface{}, error) {
|
||||
if tv != nil || *tv == 0 {
|
||||
if tv == nil || *tv == 0 {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
for s, v := range TLSVersions {
|
||||
@@ -106,7 +107,7 @@ func (tv *TLSVersion) UnmarshalJSON(data []byte) error {
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface for TLSVersion.
|
||||
func (tv *TLSVersion) MarshalJSON() ([]byte, error) {
|
||||
if tv != nil || *tv == 0 {
|
||||
if tv == nil || *tv == 0 {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
for s, v := range TLSVersions {
|
||||
@@ -117,6 +118,19 @@ func (tv *TLSVersion) MarshalJSON() ([]byte, error) {
|
||||
return nil, fmt.Errorf("unknown TLS version: %d", tv)
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface for TLSVersion.
|
||||
func (tv *TLSVersion) String() string {
|
||||
if tv == nil || *tv == 0 {
|
||||
return ""
|
||||
}
|
||||
for s, v := range TLSVersions {
|
||||
if *tv == v {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%d", tv)
|
||||
}
|
||||
|
||||
// BasicAuth contains basic HTTP authentication credentials.
|
||||
type BasicAuth struct {
|
||||
Username string `yaml:"username" json:"username"`
|
||||
@@ -235,6 +249,30 @@ func (a *OAuth2) SetDirectory(dir string) {
|
||||
a.TLSConfig.SetDirectory(dir)
|
||||
}
|
||||
|
||||
// LoadHTTPConfig parses the YAML input s into a HTTPClientConfig.
|
||||
func LoadHTTPConfig(s string) (*HTTPClientConfig, error) {
|
||||
cfg := &HTTPClientConfig{}
|
||||
err := yaml.UnmarshalStrict([]byte(s), cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// LoadHTTPConfigFile parses the given YAML file into a HTTPClientConfig.
|
||||
func LoadHTTPConfigFile(filename string) (*HTTPClientConfig, []byte, error) {
|
||||
content, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cfg, err := LoadHTTPConfig(string(content))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cfg.SetDirectory(filepath.Dir(filepath.Dir(filename)))
|
||||
return cfg, content, nil
|
||||
}
|
||||
|
||||
// HTTPClientConfig configures an HTTP client.
|
||||
type HTTPClientConfig struct {
|
||||
// The HTTP basic authentication credentials for the targets.
|
||||
@@ -251,6 +289,11 @@ type HTTPClientConfig struct {
|
||||
BearerTokenFile string `yaml:"bearer_token_file,omitempty" json:"bearer_token_file,omitempty"`
|
||||
// HTTP proxy server to use to connect to the targets.
|
||||
ProxyURL URL `yaml:"proxy_url,omitempty" json:"proxy_url,omitempty"`
|
||||
// ProxyConnectHeader optionally specifies headers to send to
|
||||
// proxies during CONNECT requests. Assume that at least _some_ of
|
||||
// these headers are going to contain secrets and use Secret as the
|
||||
// value type instead of string.
|
||||
ProxyConnectHeader Header `yaml:"proxy_connect_header,omitempty" json:"proxy_connect_header,omitempty"`
|
||||
// TLSConfig to use to connect to the targets.
|
||||
TLSConfig TLSConfig `yaml:"tls_config,omitempty" json:"tls_config,omitempty"`
|
||||
// FollowRedirects specifies whether the client should follow HTTP 3xx redirects.
|
||||
@@ -276,7 +319,8 @@ func (c *HTTPClientConfig) SetDirectory(dir string) {
|
||||
}
|
||||
|
||||
// Validate validates the HTTPClientConfig to check only one of BearerToken,
|
||||
// BasicAuth and BearerTokenFile is configured.
|
||||
// BasicAuth and BearerTokenFile is configured. It also validates that ProxyURL
|
||||
// is set if ProxyConnectHeader is set.
|
||||
func (c *HTTPClientConfig) Validate() error {
|
||||
// Backwards compatibility with the bearer_token field.
|
||||
if len(c.BearerToken) > 0 && len(c.BearerTokenFile) > 0 {
|
||||
@@ -334,6 +378,9 @@ func (c *HTTPClientConfig) Validate() error {
|
||||
return fmt.Errorf("at most one of oauth2 client_secret & client_secret_file must be configured")
|
||||
}
|
||||
}
|
||||
if len(c.ProxyConnectHeader) > 0 && (c.ProxyURL.URL == nil || c.ProxyURL.String() == "") {
|
||||
return fmt.Errorf("if proxy_connect_header is configured proxy_url must also be configured")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -462,6 +509,7 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HT
|
||||
// It is applied on request. So we leave out any timings here.
|
||||
var rt http.RoundTripper = &http.Transport{
|
||||
Proxy: http.ProxyURL(cfg.ProxyURL.URL),
|
||||
ProxyConnectHeader: cfg.ProxyConnectHeader.HTTPHeader(),
|
||||
MaxIdleConns: 20000,
|
||||
MaxIdleConnsPerHost: 1000, // see https://github.com/golang/go/issues/13801
|
||||
DisableKeepAlives: !opts.keepAlivesEnabled,
|
||||
@@ -527,7 +575,7 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HT
|
||||
return newRT(tlsConfig)
|
||||
}
|
||||
|
||||
return NewTLSRoundTripper(tlsConfig, cfg.TLSConfig.CAFile, newRT)
|
||||
return NewTLSRoundTripper(tlsConfig, cfg.TLSConfig.CAFile, cfg.TLSConfig.CertFile, cfg.TLSConfig.KeyFile, newRT)
|
||||
}
|
||||
|
||||
type authorizationCredentialsRoundTripper struct {
|
||||
@@ -571,7 +619,7 @@ func NewAuthorizationCredentialsFileRoundTripper(authType, authCredentialsFile s
|
||||
|
||||
func (rt *authorizationCredentialsFileRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if len(req.Header.Get("Authorization")) == 0 {
|
||||
b, err := ioutil.ReadFile(rt.authCredentialsFile)
|
||||
b, err := os.ReadFile(rt.authCredentialsFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read authorization credentials file %s: %s", rt.authCredentialsFile, err)
|
||||
}
|
||||
@@ -609,7 +657,7 @@ func (rt *basicAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, e
|
||||
}
|
||||
req = cloneRequest(req)
|
||||
if rt.passwordFile != "" {
|
||||
bs, err := ioutil.ReadFile(rt.passwordFile)
|
||||
bs, err := os.ReadFile(rt.passwordFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read basic auth password file %s: %s", rt.passwordFile, err)
|
||||
}
|
||||
@@ -651,7 +699,7 @@ func (rt *oauth2RoundTripper) RoundTrip(req *http.Request) (*http.Response, erro
|
||||
)
|
||||
|
||||
if rt.config.ClientSecretFile != "" {
|
||||
data, err := ioutil.ReadFile(rt.config.ClientSecretFile)
|
||||
data, err := os.ReadFile(rt.config.ClientSecretFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read oauth2 client secret file %s: %s", rt.config.ClientSecretFile, err)
|
||||
}
|
||||
@@ -696,7 +744,7 @@ func (rt *oauth2RoundTripper) RoundTrip(req *http.Request) (*http.Response, erro
|
||||
if len(rt.config.TLSConfig.CAFile) == 0 {
|
||||
t, _ = tlsTransport(tlsConfig)
|
||||
} else {
|
||||
t, err = NewTLSRoundTripper(tlsConfig, rt.config.TLSConfig.CAFile, tlsTransport)
|
||||
t, err = NewTLSRoundTripper(tlsConfig, rt.config.TLSConfig.CAFile, rt.config.TLSConfig.CertFile, rt.config.TLSConfig.KeyFile, tlsTransport)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -766,6 +814,13 @@ func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) {
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: cfg.InsecureSkipVerify,
|
||||
MinVersion: uint16(cfg.MinVersion),
|
||||
MaxVersion: uint16(cfg.MaxVersion),
|
||||
}
|
||||
|
||||
if cfg.MaxVersion != 0 && cfg.MinVersion != 0 {
|
||||
if cfg.MaxVersion < cfg.MinVersion {
|
||||
return nil, fmt.Errorf("tls_config.max_version must be greater than or equal to tls_config.min_version if both are specified")
|
||||
}
|
||||
}
|
||||
|
||||
// If a CA cert is provided then let's read it in so we can validate the
|
||||
@@ -813,6 +868,8 @@ type TLSConfig struct {
|
||||
InsecureSkipVerify bool `yaml:"insecure_skip_verify" json:"insecure_skip_verify"`
|
||||
// Minimum TLS version.
|
||||
MinVersion TLSVersion `yaml:"min_version,omitempty" json:"min_version,omitempty"`
|
||||
// Maximum TLS version.
|
||||
MaxVersion TLSVersion `yaml:"max_version,omitempty" json:"max_version,omitempty"`
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
@@ -825,18 +882,45 @@ func (c *TLSConfig) SetDirectory(dir string) {
|
||||
c.KeyFile = JoinDir(dir, c.KeyFile)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *TLSConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
type plain TLSConfig
|
||||
return unmarshal((*plain)(c))
|
||||
}
|
||||
|
||||
// readCertAndKey reads the cert and key files from the disk.
|
||||
func readCertAndKey(certFile, keyFile string) ([]byte, []byte, error) {
|
||||
certData, err := os.ReadFile(certFile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
keyData, err := os.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return certData, keyData, nil
|
||||
}
|
||||
|
||||
// getClientCertificate reads the pair of client cert and key from disk and returns a tls.Certificate.
|
||||
func (c *TLSConfig) getClientCertificate(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||
cert, err := tls.LoadX509KeyPair(c.CertFile, c.KeyFile)
|
||||
func (c *TLSConfig) getClientCertificate(_ *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||
certData, keyData, err := readCertAndKey(c.CertFile, c.KeyFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read specified client cert (%s) & key (%s): %s", c.CertFile, c.KeyFile, err)
|
||||
}
|
||||
|
||||
cert, err := tls.X509KeyPair(certData, keyData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to use specified client cert (%s) & key (%s): %s", c.CertFile, c.KeyFile, err)
|
||||
}
|
||||
|
||||
return &cert, nil
|
||||
}
|
||||
|
||||
// readCAFile reads the CA cert file from disk.
|
||||
func readCAFile(f string) ([]byte, error) {
|
||||
data, err := ioutil.ReadFile(f)
|
||||
data, err := os.ReadFile(f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load specified CA cert %s: %s", f, err)
|
||||
}
|
||||
@@ -856,23 +940,30 @@ func updateRootCA(cfg *tls.Config, b []byte) bool {
|
||||
// tlsRoundTripper is a RoundTripper that updates automatically its TLS
|
||||
// configuration whenever the content of the CA file changes.
|
||||
type tlsRoundTripper struct {
|
||||
caFile string
|
||||
caFile string
|
||||
certFile string
|
||||
keyFile string
|
||||
|
||||
// newRT returns a new RoundTripper.
|
||||
newRT func(*tls.Config) (http.RoundTripper, error)
|
||||
|
||||
mtx sync.RWMutex
|
||||
rt http.RoundTripper
|
||||
hashCAFile []byte
|
||||
tlsConfig *tls.Config
|
||||
mtx sync.RWMutex
|
||||
rt http.RoundTripper
|
||||
hashCAFile []byte
|
||||
hashCertFile []byte
|
||||
hashKeyFile []byte
|
||||
tlsConfig *tls.Config
|
||||
}
|
||||
|
||||
func NewTLSRoundTripper(
|
||||
cfg *tls.Config,
|
||||
caFile string,
|
||||
caFile, certFile, keyFile string,
|
||||
newRT func(*tls.Config) (http.RoundTripper, error),
|
||||
) (http.RoundTripper, error) {
|
||||
t := &tlsRoundTripper{
|
||||
caFile: caFile,
|
||||
certFile: certFile,
|
||||
keyFile: keyFile,
|
||||
newRT: newRT,
|
||||
tlsConfig: cfg,
|
||||
}
|
||||
@@ -882,7 +973,7 @@ func NewTLSRoundTripper(
|
||||
return nil, err
|
||||
}
|
||||
t.rt = rt
|
||||
_, t.hashCAFile, err = t.getCAWithHash()
|
||||
_, t.hashCAFile, t.hashCertFile, t.hashKeyFile, err = t.getTLSFilesWithHash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -890,25 +981,36 @@ func NewTLSRoundTripper(
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (t *tlsRoundTripper) getCAWithHash() ([]byte, []byte, error) {
|
||||
b, err := readCAFile(t.caFile)
|
||||
func (t *tlsRoundTripper) getTLSFilesWithHash() ([]byte, []byte, []byte, []byte, error) {
|
||||
b1, err := readCAFile(t.caFile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
h := sha256.Sum256(b)
|
||||
return b, h[:], nil
|
||||
h1 := sha256.Sum256(b1)
|
||||
|
||||
var h2, h3 [32]byte
|
||||
if t.certFile != "" {
|
||||
b2, b3, err := readCertAndKey(t.certFile, t.keyFile)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
h2, h3 = sha256.Sum256(b2), sha256.Sum256(b3)
|
||||
}
|
||||
|
||||
return b1, h1[:], h2[:], h3[:], nil
|
||||
}
|
||||
|
||||
// RoundTrip implements the http.RoundTrip interface.
|
||||
func (t *tlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
b, h, err := t.getCAWithHash()
|
||||
caData, caHash, certHash, keyHash, err := t.getTLSFilesWithHash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.mtx.RLock()
|
||||
equal := bytes.Equal(h[:], t.hashCAFile)
|
||||
equal := bytes.Equal(caHash[:], t.hashCAFile) &&
|
||||
bytes.Equal(certHash[:], t.hashCertFile) &&
|
||||
bytes.Equal(keyHash[:], t.hashKeyFile)
|
||||
rt := t.rt
|
||||
t.mtx.RUnlock()
|
||||
if equal {
|
||||
@@ -917,8 +1019,10 @@ func (t *tlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
}
|
||||
|
||||
// Create a new RoundTripper.
|
||||
// The cert and key files are read separately by the client
|
||||
// using GetClientCertificate.
|
||||
tlsConfig := t.tlsConfig.Clone()
|
||||
if !updateRootCA(tlsConfig, b) {
|
||||
if !updateRootCA(tlsConfig, caData) {
|
||||
return nil, fmt.Errorf("unable to use specified CA cert %s", t.caFile)
|
||||
}
|
||||
rt, err = t.newRT(tlsConfig)
|
||||
@@ -929,7 +1033,9 @@ func (t *tlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
|
||||
t.mtx.Lock()
|
||||
t.rt = rt
|
||||
t.hashCAFile = h[:]
|
||||
t.hashCAFile = caHash[:]
|
||||
t.hashCertFile = certHash[:]
|
||||
t.hashKeyFile = keyHash[:]
|
||||
t.mtx.Unlock()
|
||||
|
||||
return rt.RoundTrip(req)
|
||||
|
||||
4
vendor/github.com/prometheus/common/expfmt/fuzz.go
generated
vendored
4
vendor/github.com/prometheus/common/expfmt/fuzz.go
generated
vendored
@@ -21,8 +21,8 @@ import "bytes"
|
||||
|
||||
// Fuzz text metric parser with with github.com/dvyukov/go-fuzz:
|
||||
//
|
||||
// go-fuzz-build github.com/prometheus/common/expfmt
|
||||
// go-fuzz -bin expfmt-fuzz.zip -workdir fuzz
|
||||
// go-fuzz-build github.com/prometheus/common/expfmt
|
||||
// go-fuzz -bin expfmt-fuzz.zip -workdir fuzz
|
||||
//
|
||||
// Further input samples should go in the folder fuzz/corpus.
|
||||
func Fuzz(in []byte) int {
|
||||
|
||||
22
vendor/github.com/prometheus/common/expfmt/openmetrics_create.go
generated
vendored
22
vendor/github.com/prometheus/common/expfmt/openmetrics_create.go
generated
vendored
@@ -46,20 +46,20 @@ import (
|
||||
// missing features and peculiarities to avoid complications when switching from
|
||||
// Prometheus to OpenMetrics or vice versa:
|
||||
//
|
||||
// - Counters are expected to have the `_total` suffix in their metric name. In
|
||||
// the output, the suffix will be truncated from the `# TYPE` and `# HELP`
|
||||
// line. A counter with a missing `_total` suffix is not an error. However,
|
||||
// its type will be set to `unknown` in that case to avoid invalid OpenMetrics
|
||||
// output.
|
||||
// - Counters are expected to have the `_total` suffix in their metric name. In
|
||||
// the output, the suffix will be truncated from the `# TYPE` and `# HELP`
|
||||
// line. A counter with a missing `_total` suffix is not an error. However,
|
||||
// its type will be set to `unknown` in that case to avoid invalid OpenMetrics
|
||||
// output.
|
||||
//
|
||||
// - No support for the following (optional) features: `# UNIT` line, `_created`
|
||||
// line, info type, stateset type, gaugehistogram type.
|
||||
// - No support for the following (optional) features: `# UNIT` line, `_created`
|
||||
// line, info type, stateset type, gaugehistogram type.
|
||||
//
|
||||
// - The size of exemplar labels is not checked (i.e. it's possible to create
|
||||
// exemplars that are larger than allowed by the OpenMetrics specification).
|
||||
// - The size of exemplar labels is not checked (i.e. it's possible to create
|
||||
// exemplars that are larger than allowed by the OpenMetrics specification).
|
||||
//
|
||||
// - The value of Counters is not checked. (OpenMetrics doesn't allow counters
|
||||
// with a `NaN` value.)
|
||||
// - The value of Counters is not checked. (OpenMetrics doesn't allow counters
|
||||
// with a `NaN` value.)
|
||||
func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int, err error) {
|
||||
name := in.GetName()
|
||||
if name == "" {
|
||||
|
||||
3
vendor/github.com/prometheus/common/expfmt/text_create.go
generated
vendored
3
vendor/github.com/prometheus/common/expfmt/text_create.go
generated
vendored
@@ -17,7 +17,6 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -44,7 +43,7 @@ const (
|
||||
var (
|
||||
bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return bufio.NewWriter(ioutil.Discard)
|
||||
return bufio.NewWriter(io.Discard)
|
||||
},
|
||||
}
|
||||
numBufPool = sync.Pool{
|
||||
|
||||
22
vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go
generated
vendored
22
vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go
generated
vendored
@@ -11,18 +11,18 @@ Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
Neither the name of the Open Knowledge Foundation Ltd. nor the
|
||||
names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
Neither the name of the Open Knowledge Foundation Ltd. nor the
|
||||
names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -35,8 +35,6 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
*/
|
||||
package goautoneg
|
||||
|
||||
|
||||
201
vendor/github.com/prometheus/common/sigv4/LICENSE
generated
vendored
Normal file
201
vendor/github.com/prometheus/common/sigv4/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed 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.
|
||||
22
vendor/github.com/prometheus/common/sigv4/Makefile
generated
vendored
Normal file
22
vendor/github.com/prometheus/common/sigv4/Makefile
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# Copyright 2018 The Prometheus Authors
|
||||
# Licensed 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.
|
||||
|
||||
include ../Makefile.common
|
||||
|
||||
.PHONY: test
|
||||
@echo ">> Running sigv4 tests"
|
||||
test:: deps check_license unused common-test
|
||||
|
||||
ifeq (,$(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(7|8|9|10)\.'))
|
||||
test:: lint
|
||||
endif
|
||||
137
vendor/github.com/prometheus/common/sigv4/sigv4.go
generated
vendored
Normal file
137
vendor/github.com/prometheus/common/sigv4/sigv4.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// Licensed 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 sigv4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
signer "github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||
)
|
||||
|
||||
var sigv4HeaderDenylist = []string{
|
||||
"uber-trace-id",
|
||||
}
|
||||
|
||||
type sigV4RoundTripper struct {
|
||||
region string
|
||||
next http.RoundTripper
|
||||
pool sync.Pool
|
||||
|
||||
signer *signer.Signer
|
||||
}
|
||||
|
||||
// NewSigV4RoundTripper returns a new http.RoundTripper that will sign requests
|
||||
// using Amazon's Signature Verification V4 signing procedure. The request will
|
||||
// then be handed off to the next RoundTripper provided by next. If next is nil,
|
||||
// http.DefaultTransport will be used.
|
||||
//
|
||||
// Credentials for signing are retrieved using the the default AWS credential
|
||||
// chain. If credentials cannot be found, an error will be returned.
|
||||
func NewSigV4RoundTripper(cfg *SigV4Config, next http.RoundTripper) (http.RoundTripper, error) {
|
||||
if next == nil {
|
||||
next = http.DefaultTransport
|
||||
}
|
||||
|
||||
creds := credentials.NewStaticCredentials(cfg.AccessKey, string(cfg.SecretKey), "")
|
||||
if cfg.AccessKey == "" && cfg.SecretKey == "" {
|
||||
creds = nil
|
||||
}
|
||||
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
Config: aws.Config{
|
||||
Region: aws.String(cfg.Region),
|
||||
Credentials: creds,
|
||||
},
|
||||
Profile: cfg.Profile,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create new AWS session: %w", err)
|
||||
}
|
||||
if _, err := sess.Config.Credentials.Get(); err != nil {
|
||||
return nil, fmt.Errorf("could not get SigV4 credentials: %w", err)
|
||||
}
|
||||
if aws.StringValue(sess.Config.Region) == "" {
|
||||
return nil, fmt.Errorf("region not configured in sigv4 or in default credentials chain")
|
||||
}
|
||||
|
||||
signerCreds := sess.Config.Credentials
|
||||
if cfg.RoleARN != "" {
|
||||
signerCreds = stscreds.NewCredentials(sess, cfg.RoleARN)
|
||||
}
|
||||
|
||||
rt := &sigV4RoundTripper{
|
||||
region: cfg.Region,
|
||||
next: next,
|
||||
signer: signer.NewSigner(signerCreds),
|
||||
}
|
||||
rt.pool.New = rt.newBuf
|
||||
return rt, nil
|
||||
}
|
||||
|
||||
func (rt *sigV4RoundTripper) newBuf() interface{} {
|
||||
return bytes.NewBuffer(make([]byte, 0, 1024))
|
||||
}
|
||||
|
||||
func (rt *sigV4RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
// rt.signer.Sign needs a seekable body, so we replace the body with a
|
||||
// buffered reader filled with the contents of original body.
|
||||
buf := rt.pool.Get().(*bytes.Buffer)
|
||||
defer func() {
|
||||
buf.Reset()
|
||||
rt.pool.Put(buf)
|
||||
}()
|
||||
if _, err := io.Copy(buf, req.Body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Close the original body since we don't need it anymore.
|
||||
_ = req.Body.Close()
|
||||
|
||||
// Ensure our seeker is back at the start of the buffer once we return.
|
||||
var seeker io.ReadSeeker = bytes.NewReader(buf.Bytes())
|
||||
defer func() {
|
||||
_, _ = seeker.Seek(0, io.SeekStart)
|
||||
}()
|
||||
req.Body = ioutil.NopCloser(seeker)
|
||||
|
||||
// Clone the request and trim out headers that we don't want to sign.
|
||||
signReq := req.Clone(req.Context())
|
||||
for _, header := range sigv4HeaderDenylist {
|
||||
signReq.Header.Del(header)
|
||||
}
|
||||
|
||||
headers, err := rt.signer.Sign(signReq, seeker, "aps", rt.region, time.Now().UTC())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to sign request: %w", err)
|
||||
}
|
||||
|
||||
// Copy over signed headers. Authorization header is not returned by
|
||||
// rt.signer.Sign and needs to be copied separately.
|
||||
for k, v := range headers {
|
||||
req.Header[textproto.CanonicalMIMEHeaderKey(k)] = v
|
||||
}
|
||||
req.Header.Set("Authorization", signReq.Header.Get("Authorization"))
|
||||
|
||||
return rt.next.RoundTrip(req)
|
||||
}
|
||||
47
vendor/github.com/prometheus/common/sigv4/sigv4_config.go
generated
vendored
Normal file
47
vendor/github.com/prometheus/common/sigv4/sigv4_config.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// Licensed 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 sigv4
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/common/config"
|
||||
)
|
||||
|
||||
// SigV4Config is the configuration for signing remote write requests with
|
||||
// AWS's SigV4 verification process. Empty values will be retrieved using the
|
||||
// AWS default credentials chain.
|
||||
type SigV4Config struct {
|
||||
Region string `yaml:"region,omitempty"`
|
||||
AccessKey string `yaml:"access_key,omitempty"`
|
||||
SecretKey config.Secret `yaml:"secret_key,omitempty"`
|
||||
Profile string `yaml:"profile,omitempty"`
|
||||
RoleARN string `yaml:"role_arn,omitempty"`
|
||||
}
|
||||
|
||||
func (c *SigV4Config) Validate() error {
|
||||
if (c.AccessKey == "") != (c.SecretKey == "") {
|
||||
return fmt.Errorf("must provide a AWS SigV4 Access key and Secret Key if credentials are specified in the SigV4 config")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *SigV4Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
type plain SigV4Config
|
||||
*c = SigV4Config{}
|
||||
if err := unmarshal((*plain)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Validate()
|
||||
}
|
||||
100
vendor/github.com/prometheus/common/version/info.go
generated
vendored
Normal file
100
vendor/github.com/prometheus/common/version/info.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright 2016 The Prometheus Authors
|
||||
// Licensed 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 version
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// Build information. Populated at build-time.
|
||||
var (
|
||||
Version string
|
||||
Revision string
|
||||
Branch string
|
||||
BuildUser string
|
||||
BuildDate string
|
||||
GoVersion = runtime.Version()
|
||||
GoOS = runtime.GOOS
|
||||
GoArch = runtime.GOARCH
|
||||
)
|
||||
|
||||
// NewCollector returns a collector that exports metrics about current version
|
||||
// information.
|
||||
func NewCollector(program string) prometheus.Collector {
|
||||
return prometheus.NewGaugeFunc(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: program,
|
||||
Name: "build_info",
|
||||
Help: fmt.Sprintf(
|
||||
"A metric with a constant '1' value labeled by version, revision, branch, goversion from which %s was built, and the goos and goarch for the build.",
|
||||
program,
|
||||
),
|
||||
ConstLabels: prometheus.Labels{
|
||||
"version": Version,
|
||||
"revision": getRevision(),
|
||||
"branch": Branch,
|
||||
"goversion": GoVersion,
|
||||
"goos": GoOS,
|
||||
"goarch": GoArch,
|
||||
},
|
||||
},
|
||||
func() float64 { return 1 },
|
||||
)
|
||||
}
|
||||
|
||||
// versionInfoTmpl contains the template used by Info.
|
||||
var versionInfoTmpl = `
|
||||
{{.program}}, version {{.version}} (branch: {{.branch}}, revision: {{.revision}})
|
||||
build user: {{.buildUser}}
|
||||
build date: {{.buildDate}}
|
||||
go version: {{.goVersion}}
|
||||
platform: {{.platform}}
|
||||
`
|
||||
|
||||
// Print returns version information.
|
||||
func Print(program string) string {
|
||||
m := map[string]string{
|
||||
"program": program,
|
||||
"version": Version,
|
||||
"revision": getRevision(),
|
||||
"branch": Branch,
|
||||
"buildUser": BuildUser,
|
||||
"buildDate": BuildDate,
|
||||
"goVersion": GoVersion,
|
||||
"platform": GoOS + "/" + GoArch,
|
||||
}
|
||||
t := template.Must(template.New("version").Parse(versionInfoTmpl))
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := t.ExecuteTemplate(&buf, "version", m); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
// Info returns version, branch and revision information.
|
||||
func Info() string {
|
||||
return fmt.Sprintf("(version=%s, branch=%s, revision=%s)", Version, Branch, getRevision())
|
||||
}
|
||||
|
||||
// BuildContext returns goVersion, platform, buildUser and buildDate information.
|
||||
func BuildContext() string {
|
||||
return fmt.Sprintf("(go=%s, platform=%s, user=%s, date=%s)", GoVersion, GoOS+"/"+GoArch, BuildUser, BuildDate)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The Prometheus Authors
|
||||
// Copyright 2022 The Prometheus Authors
|
||||
// Licensed 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
|
||||
@@ -11,14 +11,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package exemplar
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
import "github.com/prometheus/prometheus/pkg/labels"
|
||||
package version
|
||||
|
||||
// Exemplar is additional information associated with a time series.
|
||||
type Exemplar struct {
|
||||
Labels labels.Labels
|
||||
Value float64
|
||||
HasTs bool
|
||||
Ts int64
|
||||
func getRevision() string {
|
||||
return Revision
|
||||
}
|
||||
58
vendor/github.com/prometheus/common/version/info_go118.go
generated
vendored
Normal file
58
vendor/github.com/prometheus/common/version/info_go118.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2022 The Prometheus Authors
|
||||
// Licensed 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.
|
||||
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package version
|
||||
|
||||
import "runtime/debug"
|
||||
|
||||
var computedRevision string
|
||||
|
||||
func getRevision() string {
|
||||
if Revision != "" {
|
||||
return Revision
|
||||
}
|
||||
return computedRevision
|
||||
}
|
||||
|
||||
func init() {
|
||||
computedRevision = computeRevision()
|
||||
}
|
||||
|
||||
func computeRevision() string {
|
||||
var (
|
||||
rev = "unknown"
|
||||
modified bool
|
||||
)
|
||||
|
||||
buildInfo, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return rev
|
||||
}
|
||||
for _, v := range buildInfo.Settings {
|
||||
if v.Key == "vcs.revision" {
|
||||
rev = v.Value
|
||||
}
|
||||
if v.Key == "vcs.modified" {
|
||||
if v.Value == "true" {
|
||||
modified = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if modified {
|
||||
return rev + "-modified"
|
||||
}
|
||||
return rev
|
||||
}
|
||||
14
vendor/github.com/prometheus/prometheus/NOTICE
generated
vendored
14
vendor/github.com/prometheus/prometheus/NOTICE
generated
vendored
@@ -91,8 +91,18 @@ https://github.com/dgryski/go-tsz
|
||||
Copyright (c) 2015,2016 Damian Gryski <damian@gryski.com>
|
||||
See https://github.com/dgryski/go-tsz/blob/master/LICENSE for license details.
|
||||
|
||||
The Go programming language
|
||||
https://go.dev/
|
||||
Copyright (c) 2009 The Go Authors
|
||||
See https://go.dev/LICENSE for license details.
|
||||
|
||||
The Codicon icon font from Microsoft
|
||||
https://github.com/microsoft/vscode-codicons
|
||||
Copyright (c) Microsoft Corporation and other contributors
|
||||
See https://github.com/microsoft/vscode-codicons/blob/main/LICENSE for license details.
|
||||
|
||||
We also use code from a large number of npm packages. For details, see:
|
||||
- https://github.com/prometheus/prometheus/blob/master/web/ui/react-app/package.json
|
||||
- https://github.com/prometheus/prometheus/blob/master/web/ui/react-app/package-lock.json
|
||||
- https://github.com/prometheus/prometheus/blob/main/web/ui/react-app/package.json
|
||||
- https://github.com/prometheus/prometheus/blob/main/web/ui/react-app/package-lock.json
|
||||
- The individual package licenses as copied from the node_modules directory can be found in
|
||||
the npm_licenses.tar.bz2 archive in release tarballs and Docker images.
|
||||
|
||||
938
vendor/github.com/prometheus/prometheus/config/config.go
generated
vendored
Normal file
938
vendor/github.com/prometheus/prometheus/config/config.go
generated
vendored
Normal file
@@ -0,0 +1,938 @@
|
||||
// Copyright 2015 The Prometheus Authors
|
||||
// Licensed 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 config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/alecthomas/units"
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/sigv4"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/model/relabel"
|
||||
)
|
||||
|
||||
var (
|
||||
patRulePath = regexp.MustCompile(`^[^*]*(\*[^/]*)?$`)
|
||||
reservedHeaders = map[string]struct{}{
|
||||
// NOTE: authorization is checked specially,
|
||||
// see RemoteWriteConfig.UnmarshalYAML.
|
||||
// "authorization": {},
|
||||
"host": {},
|
||||
"content-encoding": {},
|
||||
"content-length": {},
|
||||
"content-type": {},
|
||||
"user-agent": {},
|
||||
"connection": {},
|
||||
"keep-alive": {},
|
||||
"proxy-authenticate": {},
|
||||
"proxy-authorization": {},
|
||||
"www-authenticate": {},
|
||||
"accept-encoding": {},
|
||||
"x-prometheus-remote-write-version": {},
|
||||
"x-prometheus-remote-read-version": {},
|
||||
|
||||
// Added by SigV4.
|
||||
"x-amz-date": {},
|
||||
"x-amz-security-token": {},
|
||||
"x-amz-content-sha256": {},
|
||||
}
|
||||
)
|
||||
|
||||
// Load parses the YAML input s into a Config.
|
||||
func Load(s string, expandExternalLabels bool, logger log.Logger) (*Config, error) {
|
||||
cfg := &Config{}
|
||||
// If the entire config body is empty the UnmarshalYAML method is
|
||||
// never called. We thus have to set the DefaultConfig at the entry
|
||||
// point as well.
|
||||
*cfg = DefaultConfig
|
||||
|
||||
err := yaml.UnmarshalStrict([]byte(s), cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !expandExternalLabels {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
b := labels.ScratchBuilder{}
|
||||
cfg.GlobalConfig.ExternalLabels.Range(func(v labels.Label) {
|
||||
newV := os.Expand(v.Value, func(s string) string {
|
||||
if s == "$" {
|
||||
return "$"
|
||||
}
|
||||
if v := os.Getenv(s); v != "" {
|
||||
return v
|
||||
}
|
||||
level.Warn(logger).Log("msg", "Empty environment variable", "name", s)
|
||||
return ""
|
||||
})
|
||||
if newV != v.Value {
|
||||
level.Debug(logger).Log("msg", "External label replaced", "label", v.Name, "input", v.Value, "output", newV)
|
||||
}
|
||||
b.Add(v.Name, newV)
|
||||
})
|
||||
cfg.GlobalConfig.ExternalLabels = b.Labels()
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// LoadFile parses the given YAML file into a Config.
|
||||
func LoadFile(filename string, agentMode, expandExternalLabels bool, logger log.Logger) (*Config, error) {
|
||||
content, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg, err := Load(string(content), expandExternalLabels, logger)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing YAML file %s: %w", filename, err)
|
||||
}
|
||||
|
||||
if agentMode {
|
||||
if len(cfg.AlertingConfig.AlertmanagerConfigs) > 0 || len(cfg.AlertingConfig.AlertRelabelConfigs) > 0 {
|
||||
return nil, errors.New("field alerting is not allowed in agent mode")
|
||||
}
|
||||
|
||||
if len(cfg.RuleFiles) > 0 {
|
||||
return nil, errors.New("field rule_files is not allowed in agent mode")
|
||||
}
|
||||
|
||||
if len(cfg.RemoteReadConfigs) > 0 {
|
||||
return nil, errors.New("field remote_read is not allowed in agent mode")
|
||||
}
|
||||
}
|
||||
|
||||
cfg.SetDirectory(filepath.Dir(filename))
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// The defaults applied before parsing the respective config sections.
|
||||
var (
|
||||
// DefaultConfig is the default top-level configuration.
|
||||
DefaultConfig = Config{
|
||||
GlobalConfig: DefaultGlobalConfig,
|
||||
}
|
||||
|
||||
// DefaultGlobalConfig is the default global configuration.
|
||||
DefaultGlobalConfig = GlobalConfig{
|
||||
ScrapeInterval: model.Duration(1 * time.Minute),
|
||||
ScrapeTimeout: model.Duration(10 * time.Second),
|
||||
EvaluationInterval: model.Duration(1 * time.Minute),
|
||||
}
|
||||
|
||||
// DefaultScrapeConfig is the default scrape configuration.
|
||||
DefaultScrapeConfig = ScrapeConfig{
|
||||
// ScrapeTimeout and ScrapeInterval default to the
|
||||
// configured globals.
|
||||
MetricsPath: "/metrics",
|
||||
Scheme: "http",
|
||||
HonorLabels: false,
|
||||
HonorTimestamps: true,
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
}
|
||||
|
||||
// DefaultAlertmanagerConfig is the default alertmanager configuration.
|
||||
DefaultAlertmanagerConfig = AlertmanagerConfig{
|
||||
Scheme: "http",
|
||||
Timeout: model.Duration(10 * time.Second),
|
||||
APIVersion: AlertmanagerAPIVersionV2,
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
}
|
||||
|
||||
// DefaultRemoteWriteConfig is the default remote write configuration.
|
||||
DefaultRemoteWriteConfig = RemoteWriteConfig{
|
||||
RemoteTimeout: model.Duration(30 * time.Second),
|
||||
QueueConfig: DefaultQueueConfig,
|
||||
MetadataConfig: DefaultMetadataConfig,
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
}
|
||||
|
||||
// DefaultQueueConfig is the default remote queue configuration.
|
||||
DefaultQueueConfig = QueueConfig{
|
||||
// With a maximum of 200 shards, assuming an average of 100ms remote write
|
||||
// time and 500 samples per batch, we will be able to push 1M samples/s.
|
||||
MaxShards: 200,
|
||||
MinShards: 1,
|
||||
MaxSamplesPerSend: 500,
|
||||
|
||||
// Each shard will have a max of 2500 samples pending in its channel, plus the pending
|
||||
// samples that have been enqueued. Theoretically we should only ever have about 3000 samples
|
||||
// per shard pending. At 200 shards that's 600k.
|
||||
Capacity: 2500,
|
||||
BatchSendDeadline: model.Duration(5 * time.Second),
|
||||
|
||||
// Backoff times for retrying a batch of samples on recoverable errors.
|
||||
MinBackoff: model.Duration(30 * time.Millisecond),
|
||||
MaxBackoff: model.Duration(5 * time.Second),
|
||||
}
|
||||
|
||||
// DefaultMetadataConfig is the default metadata configuration for a remote write endpoint.
|
||||
DefaultMetadataConfig = MetadataConfig{
|
||||
Send: true,
|
||||
SendInterval: model.Duration(1 * time.Minute),
|
||||
MaxSamplesPerSend: 500,
|
||||
}
|
||||
|
||||
// DefaultRemoteReadConfig is the default remote read configuration.
|
||||
DefaultRemoteReadConfig = RemoteReadConfig{
|
||||
RemoteTimeout: model.Duration(1 * time.Minute),
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
FilterExternalLabels: true,
|
||||
}
|
||||
|
||||
// DefaultStorageConfig is the default TSDB/Exemplar storage configuration.
|
||||
DefaultStorageConfig = StorageConfig{
|
||||
ExemplarsConfig: &DefaultExemplarsConfig,
|
||||
}
|
||||
|
||||
DefaultExemplarsConfig = ExemplarsConfig{
|
||||
MaxExemplars: 100000,
|
||||
}
|
||||
)
|
||||
|
||||
// Config is the top-level configuration for Prometheus's config files.
|
||||
type Config struct {
|
||||
GlobalConfig GlobalConfig `yaml:"global"`
|
||||
AlertingConfig AlertingConfig `yaml:"alerting,omitempty"`
|
||||
RuleFiles []string `yaml:"rule_files,omitempty"`
|
||||
ScrapeConfigs []*ScrapeConfig `yaml:"scrape_configs,omitempty"`
|
||||
StorageConfig StorageConfig `yaml:"storage,omitempty"`
|
||||
TracingConfig TracingConfig `yaml:"tracing,omitempty"`
|
||||
|
||||
RemoteWriteConfigs []*RemoteWriteConfig `yaml:"remote_write,omitempty"`
|
||||
RemoteReadConfigs []*RemoteReadConfig `yaml:"remote_read,omitempty"`
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *Config) SetDirectory(dir string) {
|
||||
c.GlobalConfig.SetDirectory(dir)
|
||||
c.AlertingConfig.SetDirectory(dir)
|
||||
c.TracingConfig.SetDirectory(dir)
|
||||
for i, file := range c.RuleFiles {
|
||||
c.RuleFiles[i] = config.JoinDir(dir, file)
|
||||
}
|
||||
for _, c := range c.ScrapeConfigs {
|
||||
c.SetDirectory(dir)
|
||||
}
|
||||
for _, c := range c.RemoteWriteConfigs {
|
||||
c.SetDirectory(dir)
|
||||
}
|
||||
for _, c := range c.RemoteReadConfigs {
|
||||
c.SetDirectory(dir)
|
||||
}
|
||||
}
|
||||
|
||||
func (c Config) String() string {
|
||||
b, err := yaml.Marshal(c)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("<error creating config string: %s>", err)
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultConfig
|
||||
// We want to set c to the defaults and then overwrite it with the input.
|
||||
// To make unmarshal fill the plain data struct rather than calling UnmarshalYAML
|
||||
// again, we have to hide it using a type indirection.
|
||||
type plain Config
|
||||
if err := unmarshal((*plain)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If a global block was open but empty the default global config is overwritten.
|
||||
// We have to restore it here.
|
||||
if c.GlobalConfig.isZero() {
|
||||
c.GlobalConfig = DefaultGlobalConfig
|
||||
}
|
||||
|
||||
for _, rf := range c.RuleFiles {
|
||||
if !patRulePath.MatchString(rf) {
|
||||
return fmt.Errorf("invalid rule file path %q", rf)
|
||||
}
|
||||
}
|
||||
// Do global overrides and validate unique names.
|
||||
jobNames := map[string]struct{}{}
|
||||
for _, scfg := range c.ScrapeConfigs {
|
||||
if scfg == nil {
|
||||
return errors.New("empty or null scrape config section")
|
||||
}
|
||||
// First set the correct scrape interval, then check that the timeout
|
||||
// (inferred or explicit) is not greater than that.
|
||||
if scfg.ScrapeInterval == 0 {
|
||||
scfg.ScrapeInterval = c.GlobalConfig.ScrapeInterval
|
||||
}
|
||||
if scfg.ScrapeTimeout > scfg.ScrapeInterval {
|
||||
return fmt.Errorf("scrape timeout greater than scrape interval for scrape config with job name %q", scfg.JobName)
|
||||
}
|
||||
if scfg.ScrapeTimeout == 0 {
|
||||
if c.GlobalConfig.ScrapeTimeout > scfg.ScrapeInterval {
|
||||
scfg.ScrapeTimeout = scfg.ScrapeInterval
|
||||
} else {
|
||||
scfg.ScrapeTimeout = c.GlobalConfig.ScrapeTimeout
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := jobNames[scfg.JobName]; ok {
|
||||
return fmt.Errorf("found multiple scrape configs with job name %q", scfg.JobName)
|
||||
}
|
||||
jobNames[scfg.JobName] = struct{}{}
|
||||
}
|
||||
rwNames := map[string]struct{}{}
|
||||
for _, rwcfg := range c.RemoteWriteConfigs {
|
||||
if rwcfg == nil {
|
||||
return errors.New("empty or null remote write config section")
|
||||
}
|
||||
// Skip empty names, we fill their name with their config hash in remote write code.
|
||||
if _, ok := rwNames[rwcfg.Name]; ok && rwcfg.Name != "" {
|
||||
return fmt.Errorf("found multiple remote write configs with job name %q", rwcfg.Name)
|
||||
}
|
||||
rwNames[rwcfg.Name] = struct{}{}
|
||||
}
|
||||
rrNames := map[string]struct{}{}
|
||||
for _, rrcfg := range c.RemoteReadConfigs {
|
||||
if rrcfg == nil {
|
||||
return errors.New("empty or null remote read config section")
|
||||
}
|
||||
// Skip empty names, we fill their name with their config hash in remote read code.
|
||||
if _, ok := rrNames[rrcfg.Name]; ok && rrcfg.Name != "" {
|
||||
return fmt.Errorf("found multiple remote read configs with job name %q", rrcfg.Name)
|
||||
}
|
||||
rrNames[rrcfg.Name] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GlobalConfig configures values that are used across other configuration
|
||||
// objects.
|
||||
type GlobalConfig struct {
|
||||
// How frequently to scrape targets by default.
|
||||
ScrapeInterval model.Duration `yaml:"scrape_interval,omitempty"`
|
||||
// The default timeout when scraping targets.
|
||||
ScrapeTimeout model.Duration `yaml:"scrape_timeout,omitempty"`
|
||||
// How frequently to evaluate rules by default.
|
||||
EvaluationInterval model.Duration `yaml:"evaluation_interval,omitempty"`
|
||||
// File to which PromQL queries are logged.
|
||||
QueryLogFile string `yaml:"query_log_file,omitempty"`
|
||||
// The labels to add to any timeseries that this Prometheus instance scrapes.
|
||||
ExternalLabels labels.Labels `yaml:"external_labels,omitempty"`
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *GlobalConfig) SetDirectory(dir string) {
|
||||
c.QueryLogFile = config.JoinDir(dir, c.QueryLogFile)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *GlobalConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
// Create a clean global config as the previous one was already populated
|
||||
// by the default due to the YAML parser behavior for empty blocks.
|
||||
gc := &GlobalConfig{}
|
||||
type plain GlobalConfig
|
||||
if err := unmarshal((*plain)(gc)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := gc.ExternalLabels.Validate(func(l labels.Label) error {
|
||||
if !model.LabelName(l.Name).IsValid() {
|
||||
return fmt.Errorf("%q is not a valid label name", l.Name)
|
||||
}
|
||||
if !model.LabelValue(l.Value).IsValid() {
|
||||
return fmt.Errorf("%q is not a valid label value", l.Value)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// First set the correct scrape interval, then check that the timeout
|
||||
// (inferred or explicit) is not greater than that.
|
||||
if gc.ScrapeInterval == 0 {
|
||||
gc.ScrapeInterval = DefaultGlobalConfig.ScrapeInterval
|
||||
}
|
||||
if gc.ScrapeTimeout > gc.ScrapeInterval {
|
||||
return errors.New("global scrape timeout greater than scrape interval")
|
||||
}
|
||||
if gc.ScrapeTimeout == 0 {
|
||||
if DefaultGlobalConfig.ScrapeTimeout > gc.ScrapeInterval {
|
||||
gc.ScrapeTimeout = gc.ScrapeInterval
|
||||
} else {
|
||||
gc.ScrapeTimeout = DefaultGlobalConfig.ScrapeTimeout
|
||||
}
|
||||
}
|
||||
if gc.EvaluationInterval == 0 {
|
||||
gc.EvaluationInterval = DefaultGlobalConfig.EvaluationInterval
|
||||
}
|
||||
*c = *gc
|
||||
return nil
|
||||
}
|
||||
|
||||
// isZero returns true iff the global config is the zero value.
|
||||
func (c *GlobalConfig) isZero() bool {
|
||||
return c.ExternalLabels.IsEmpty() &&
|
||||
c.ScrapeInterval == 0 &&
|
||||
c.ScrapeTimeout == 0 &&
|
||||
c.EvaluationInterval == 0 &&
|
||||
c.QueryLogFile == ""
|
||||
}
|
||||
|
||||
// ScrapeConfig configures a scraping unit for Prometheus.
|
||||
type ScrapeConfig struct {
|
||||
// The job name to which the job label is set by default.
|
||||
JobName string `yaml:"job_name"`
|
||||
// Indicator whether the scraped metrics should remain unmodified.
|
||||
HonorLabels bool `yaml:"honor_labels,omitempty"`
|
||||
// Indicator whether the scraped timestamps should be respected.
|
||||
HonorTimestamps bool `yaml:"honor_timestamps"`
|
||||
// A set of query parameters with which the target is scraped.
|
||||
Params url.Values `yaml:"params,omitempty"`
|
||||
// How frequently to scrape the targets of this scrape config.
|
||||
ScrapeInterval model.Duration `yaml:"scrape_interval,omitempty"`
|
||||
// The timeout for scraping targets of this config.
|
||||
ScrapeTimeout model.Duration `yaml:"scrape_timeout,omitempty"`
|
||||
// The HTTP resource path on which to fetch metrics from targets.
|
||||
MetricsPath string `yaml:"metrics_path,omitempty"`
|
||||
// The URL scheme with which to fetch metrics from targets.
|
||||
Scheme string `yaml:"scheme,omitempty"`
|
||||
// An uncompressed response body larger than this many bytes will cause the
|
||||
// scrape to fail. 0 means no limit.
|
||||
BodySizeLimit units.Base2Bytes `yaml:"body_size_limit,omitempty"`
|
||||
// More than this many samples post metric-relabeling will cause the scrape to
|
||||
// fail.
|
||||
SampleLimit uint `yaml:"sample_limit,omitempty"`
|
||||
// More than this many targets after the target relabeling will cause the
|
||||
// scrapes to fail.
|
||||
TargetLimit uint `yaml:"target_limit,omitempty"`
|
||||
// More than this many labels post metric-relabeling will cause the scrape to
|
||||
// fail.
|
||||
LabelLimit uint `yaml:"label_limit,omitempty"`
|
||||
// More than this label name length post metric-relabeling will cause the
|
||||
// scrape to fail.
|
||||
LabelNameLengthLimit uint `yaml:"label_name_length_limit,omitempty"`
|
||||
// More than this label value length post metric-relabeling will cause the
|
||||
// scrape to fail.
|
||||
LabelValueLengthLimit uint `yaml:"label_value_length_limit,omitempty"`
|
||||
|
||||
// We cannot do proper Go type embedding below as the parser will then parse
|
||||
// values arbitrarily into the overflow maps of further-down types.
|
||||
|
||||
ServiceDiscoveryConfigs discovery.Configs `yaml:"-"`
|
||||
HTTPClientConfig config.HTTPClientConfig `yaml:",inline"`
|
||||
|
||||
// List of target relabel configurations.
|
||||
RelabelConfigs []*relabel.Config `yaml:"relabel_configs,omitempty"`
|
||||
// List of metric relabel configurations.
|
||||
MetricRelabelConfigs []*relabel.Config `yaml:"metric_relabel_configs,omitempty"`
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *ScrapeConfig) SetDirectory(dir string) {
|
||||
c.ServiceDiscoveryConfigs.SetDirectory(dir)
|
||||
c.HTTPClientConfig.SetDirectory(dir)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *ScrapeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultScrapeConfig
|
||||
if err := discovery.UnmarshalYAMLWithInlineConfigs(c, unmarshal); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(c.JobName) == 0 {
|
||||
return errors.New("job_name is empty")
|
||||
}
|
||||
|
||||
// The UnmarshalYAML method of HTTPClientConfig is not being called because it's not a pointer.
|
||||
// We cannot make it a pointer as the parser panics for inlined pointer structs.
|
||||
// Thus we just do its validation here.
|
||||
if err := c.HTTPClientConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check for users putting URLs in target groups.
|
||||
if len(c.RelabelConfigs) == 0 {
|
||||
if err := checkStaticTargets(c.ServiceDiscoveryConfigs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, rlcfg := range c.RelabelConfigs {
|
||||
if rlcfg == nil {
|
||||
return errors.New("empty or null target relabeling rule in scrape config")
|
||||
}
|
||||
}
|
||||
for _, rlcfg := range c.MetricRelabelConfigs {
|
||||
if rlcfg == nil {
|
||||
return errors.New("empty or null metric relabeling rule in scrape config")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalYAML implements the yaml.Marshaler interface.
|
||||
func (c *ScrapeConfig) MarshalYAML() (interface{}, error) {
|
||||
return discovery.MarshalYAMLWithInlineConfigs(c)
|
||||
}
|
||||
|
||||
// StorageConfig configures runtime reloadable configuration options.
|
||||
type StorageConfig struct {
|
||||
TSDBConfig *TSDBConfig `yaml:"tsdb,omitempty"`
|
||||
ExemplarsConfig *ExemplarsConfig `yaml:"exemplars,omitempty"`
|
||||
}
|
||||
|
||||
// TSDBConfig configures runtime reloadable configuration options.
|
||||
type TSDBConfig struct {
|
||||
// OutOfOrderTimeWindow sets how long back in time an out-of-order sample can be inserted
|
||||
// into the TSDB. This flag is typically set while unmarshaling the configuration file and translating
|
||||
// OutOfOrderTimeWindowFlag's duration. The unit of this flag is expected to be the same as any
|
||||
// other timestamp in the TSDB.
|
||||
OutOfOrderTimeWindow int64
|
||||
|
||||
// OutOfOrderTimeWindowFlag holds the parsed duration from the config file.
|
||||
// During unmarshall, this is converted into milliseconds and stored in OutOfOrderTimeWindow.
|
||||
// This should not be used directly and must be converted into OutOfOrderTimeWindow.
|
||||
OutOfOrderTimeWindowFlag model.Duration `yaml:"out_of_order_time_window,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (t *TSDBConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*t = TSDBConfig{}
|
||||
type plain TSDBConfig
|
||||
if err := unmarshal((*plain)(t)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.OutOfOrderTimeWindow = time.Duration(t.OutOfOrderTimeWindowFlag).Milliseconds()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type TracingClientType string
|
||||
|
||||
const (
|
||||
TracingClientHTTP TracingClientType = "http"
|
||||
TracingClientGRPC TracingClientType = "grpc"
|
||||
|
||||
GzipCompression = "gzip"
|
||||
)
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (t *TracingClientType) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*t = TracingClientType("")
|
||||
type plain TracingClientType
|
||||
if err := unmarshal((*plain)(t)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if *t != TracingClientHTTP && *t != TracingClientGRPC {
|
||||
return fmt.Errorf("expected tracing client type to be to be %s or %s, but got %s",
|
||||
TracingClientHTTP, TracingClientGRPC, *t,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TracingConfig configures the tracing options.
|
||||
type TracingConfig struct {
|
||||
ClientType TracingClientType `yaml:"client_type,omitempty"`
|
||||
Endpoint string `yaml:"endpoint,omitempty"`
|
||||
SamplingFraction float64 `yaml:"sampling_fraction,omitempty"`
|
||||
Insecure bool `yaml:"insecure,omitempty"`
|
||||
TLSConfig config.TLSConfig `yaml:"tls_config,omitempty"`
|
||||
Headers map[string]string `yaml:"headers,omitempty"`
|
||||
Compression string `yaml:"compression,omitempty"`
|
||||
Timeout model.Duration `yaml:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (t *TracingConfig) SetDirectory(dir string) {
|
||||
t.TLSConfig.SetDirectory(dir)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (t *TracingConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*t = TracingConfig{
|
||||
ClientType: TracingClientGRPC,
|
||||
}
|
||||
type plain TracingConfig
|
||||
if err := unmarshal((*plain)(t)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validateHeadersForTracing(t.Headers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t.Endpoint == "" {
|
||||
return errors.New("tracing endpoint must be set")
|
||||
}
|
||||
|
||||
if t.Compression != "" && t.Compression != GzipCompression {
|
||||
return fmt.Errorf("invalid compression type %s provided, valid options: %s",
|
||||
t.Compression, GzipCompression)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExemplarsConfig configures runtime reloadable configuration options.
|
||||
type ExemplarsConfig struct {
|
||||
// MaxExemplars sets the size, in # of exemplars stored, of the single circular buffer used to store exemplars in memory.
|
||||
// Use a value of 0 or less than 0 to disable the storage without having to restart Prometheus.
|
||||
MaxExemplars int64 `yaml:"max_exemplars,omitempty"`
|
||||
}
|
||||
|
||||
// AlertingConfig configures alerting and alertmanager related configs.
|
||||
type AlertingConfig struct {
|
||||
AlertRelabelConfigs []*relabel.Config `yaml:"alert_relabel_configs,omitempty"`
|
||||
AlertmanagerConfigs AlertmanagerConfigs `yaml:"alertmanagers,omitempty"`
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *AlertingConfig) SetDirectory(dir string) {
|
||||
for _, c := range c.AlertmanagerConfigs {
|
||||
c.SetDirectory(dir)
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *AlertingConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
// Create a clean global config as the previous one was already populated
|
||||
// by the default due to the YAML parser behavior for empty blocks.
|
||||
*c = AlertingConfig{}
|
||||
type plain AlertingConfig
|
||||
if err := unmarshal((*plain)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, rlcfg := range c.AlertRelabelConfigs {
|
||||
if rlcfg == nil {
|
||||
return errors.New("empty or null alert relabeling rule")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AlertmanagerConfigs is a slice of *AlertmanagerConfig.
|
||||
type AlertmanagerConfigs []*AlertmanagerConfig
|
||||
|
||||
// ToMap converts a slice of *AlertmanagerConfig to a map.
|
||||
func (a AlertmanagerConfigs) ToMap() map[string]*AlertmanagerConfig {
|
||||
ret := make(map[string]*AlertmanagerConfig)
|
||||
for i := range a {
|
||||
ret[fmt.Sprintf("config-%d", i)] = a[i]
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// AlertmanagerAPIVersion represents a version of the
|
||||
// github.com/prometheus/alertmanager/api, e.g. 'v1' or 'v2'.
|
||||
type AlertmanagerAPIVersion string
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (v *AlertmanagerAPIVersion) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*v = AlertmanagerAPIVersion("")
|
||||
type plain AlertmanagerAPIVersion
|
||||
if err := unmarshal((*plain)(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, supportedVersion := range SupportedAlertmanagerAPIVersions {
|
||||
if *v == supportedVersion {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("expected Alertmanager api version to be one of %v but got %v", SupportedAlertmanagerAPIVersions, *v)
|
||||
}
|
||||
|
||||
const (
|
||||
// AlertmanagerAPIVersionV1 represents
|
||||
// github.com/prometheus/alertmanager/api/v1.
|
||||
AlertmanagerAPIVersionV1 AlertmanagerAPIVersion = "v1"
|
||||
// AlertmanagerAPIVersionV2 represents
|
||||
// github.com/prometheus/alertmanager/api/v2.
|
||||
AlertmanagerAPIVersionV2 AlertmanagerAPIVersion = "v2"
|
||||
)
|
||||
|
||||
var SupportedAlertmanagerAPIVersions = []AlertmanagerAPIVersion{
|
||||
AlertmanagerAPIVersionV1, AlertmanagerAPIVersionV2,
|
||||
}
|
||||
|
||||
// AlertmanagerConfig configures how Alertmanagers can be discovered and communicated with.
|
||||
type AlertmanagerConfig struct {
|
||||
// We cannot do proper Go type embedding below as the parser will then parse
|
||||
// values arbitrarily into the overflow maps of further-down types.
|
||||
|
||||
ServiceDiscoveryConfigs discovery.Configs `yaml:"-"`
|
||||
HTTPClientConfig config.HTTPClientConfig `yaml:",inline"`
|
||||
|
||||
// The URL scheme to use when talking to Alertmanagers.
|
||||
Scheme string `yaml:"scheme,omitempty"`
|
||||
// Path prefix to add in front of the push endpoint path.
|
||||
PathPrefix string `yaml:"path_prefix,omitempty"`
|
||||
// The timeout used when sending alerts.
|
||||
Timeout model.Duration `yaml:"timeout,omitempty"`
|
||||
|
||||
// The api version of Alertmanager.
|
||||
APIVersion AlertmanagerAPIVersion `yaml:"api_version"`
|
||||
|
||||
// List of Alertmanager relabel configurations.
|
||||
RelabelConfigs []*relabel.Config `yaml:"relabel_configs,omitempty"`
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *AlertmanagerConfig) SetDirectory(dir string) {
|
||||
c.ServiceDiscoveryConfigs.SetDirectory(dir)
|
||||
c.HTTPClientConfig.SetDirectory(dir)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *AlertmanagerConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultAlertmanagerConfig
|
||||
if err := discovery.UnmarshalYAMLWithInlineConfigs(c, unmarshal); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The UnmarshalYAML method of HTTPClientConfig is not being called because it's not a pointer.
|
||||
// We cannot make it a pointer as the parser panics for inlined pointer structs.
|
||||
// Thus we just do its validation here.
|
||||
if err := c.HTTPClientConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check for users putting URLs in target groups.
|
||||
if len(c.RelabelConfigs) == 0 {
|
||||
if err := checkStaticTargets(c.ServiceDiscoveryConfigs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, rlcfg := range c.RelabelConfigs {
|
||||
if rlcfg == nil {
|
||||
return errors.New("empty or null Alertmanager target relabeling rule")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalYAML implements the yaml.Marshaler interface.
|
||||
func (c *AlertmanagerConfig) MarshalYAML() (interface{}, error) {
|
||||
return discovery.MarshalYAMLWithInlineConfigs(c)
|
||||
}
|
||||
|
||||
func checkStaticTargets(configs discovery.Configs) error {
|
||||
for _, cfg := range configs {
|
||||
sc, ok := cfg.(discovery.StaticConfig)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, tg := range sc {
|
||||
for _, t := range tg.Targets {
|
||||
if err := CheckTargetAddress(t[model.AddressLabel]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckTargetAddress checks if target address is valid.
|
||||
func CheckTargetAddress(address model.LabelValue) error {
|
||||
// For now check for a URL, we may want to expand this later.
|
||||
if strings.Contains(string(address), "/") {
|
||||
return fmt.Errorf("%q is not a valid hostname", address)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoteWriteConfig is the configuration for writing to remote storage.
|
||||
type RemoteWriteConfig struct {
|
||||
URL *config.URL `yaml:"url"`
|
||||
RemoteTimeout model.Duration `yaml:"remote_timeout,omitempty"`
|
||||
Headers map[string]string `yaml:"headers,omitempty"`
|
||||
WriteRelabelConfigs []*relabel.Config `yaml:"write_relabel_configs,omitempty"`
|
||||
Name string `yaml:"name,omitempty"`
|
||||
SendExemplars bool `yaml:"send_exemplars,omitempty"`
|
||||
SendNativeHistograms bool `yaml:"send_native_histograms,omitempty"`
|
||||
|
||||
// We cannot do proper Go type embedding below as the parser will then parse
|
||||
// values arbitrarily into the overflow maps of further-down types.
|
||||
HTTPClientConfig config.HTTPClientConfig `yaml:",inline"`
|
||||
QueueConfig QueueConfig `yaml:"queue_config,omitempty"`
|
||||
MetadataConfig MetadataConfig `yaml:"metadata_config,omitempty"`
|
||||
SigV4Config *sigv4.SigV4Config `yaml:"sigv4,omitempty"`
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *RemoteWriteConfig) SetDirectory(dir string) {
|
||||
c.HTTPClientConfig.SetDirectory(dir)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *RemoteWriteConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultRemoteWriteConfig
|
||||
type plain RemoteWriteConfig
|
||||
if err := unmarshal((*plain)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.URL == nil {
|
||||
return errors.New("url for remote_write is empty")
|
||||
}
|
||||
for _, rlcfg := range c.WriteRelabelConfigs {
|
||||
if rlcfg == nil {
|
||||
return errors.New("empty or null relabeling rule in remote write config")
|
||||
}
|
||||
}
|
||||
if err := validateHeaders(c.Headers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The UnmarshalYAML method of HTTPClientConfig is not being called because it's not a pointer.
|
||||
// We cannot make it a pointer as the parser panics for inlined pointer structs.
|
||||
// Thus we just do its validation here.
|
||||
if err := c.HTTPClientConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
httpClientConfigAuthEnabled := c.HTTPClientConfig.BasicAuth != nil ||
|
||||
c.HTTPClientConfig.Authorization != nil || c.HTTPClientConfig.OAuth2 != nil
|
||||
|
||||
if httpClientConfigAuthEnabled && c.SigV4Config != nil {
|
||||
return fmt.Errorf("at most one of basic_auth, authorization, oauth2, & sigv4 must be configured")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateHeadersForTracing(headers map[string]string) error {
|
||||
for header := range headers {
|
||||
if strings.ToLower(header) == "authorization" {
|
||||
return errors.New("custom authorization header configuration is not yet supported")
|
||||
}
|
||||
if _, ok := reservedHeaders[strings.ToLower(header)]; ok {
|
||||
return fmt.Errorf("%s is a reserved header. It must not be changed", header)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateHeaders(headers map[string]string) error {
|
||||
for header := range headers {
|
||||
if strings.ToLower(header) == "authorization" {
|
||||
return errors.New("authorization header must be changed via the basic_auth, authorization, oauth2, or sigv4 parameter")
|
||||
}
|
||||
if _, ok := reservedHeaders[strings.ToLower(header)]; ok {
|
||||
return fmt.Errorf("%s is a reserved header. It must not be changed", header)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// QueueConfig is the configuration for the queue used to write to remote
|
||||
// storage.
|
||||
type QueueConfig struct {
|
||||
// Number of samples to buffer per shard before we block. Defaults to
|
||||
// MaxSamplesPerSend.
|
||||
Capacity int `yaml:"capacity,omitempty"`
|
||||
|
||||
// Max number of shards, i.e. amount of concurrency.
|
||||
MaxShards int `yaml:"max_shards,omitempty"`
|
||||
|
||||
// Min number of shards, i.e. amount of concurrency.
|
||||
MinShards int `yaml:"min_shards,omitempty"`
|
||||
|
||||
// Maximum number of samples per send.
|
||||
MaxSamplesPerSend int `yaml:"max_samples_per_send,omitempty"`
|
||||
|
||||
// Maximum time sample will wait in buffer.
|
||||
BatchSendDeadline model.Duration `yaml:"batch_send_deadline,omitempty"`
|
||||
|
||||
// On recoverable errors, backoff exponentially.
|
||||
MinBackoff model.Duration `yaml:"min_backoff,omitempty"`
|
||||
MaxBackoff model.Duration `yaml:"max_backoff,omitempty"`
|
||||
RetryOnRateLimit bool `yaml:"retry_on_http_429,omitempty"`
|
||||
}
|
||||
|
||||
// MetadataConfig is the configuration for sending metadata to remote
|
||||
// storage.
|
||||
type MetadataConfig struct {
|
||||
// Send controls whether we send metric metadata to remote storage.
|
||||
Send bool `yaml:"send"`
|
||||
// SendInterval controls how frequently we send metric metadata.
|
||||
SendInterval model.Duration `yaml:"send_interval"`
|
||||
// Maximum number of samples per send.
|
||||
MaxSamplesPerSend int `yaml:"max_samples_per_send,omitempty"`
|
||||
}
|
||||
|
||||
// RemoteReadConfig is the configuration for reading from remote storage.
|
||||
type RemoteReadConfig struct {
|
||||
URL *config.URL `yaml:"url"`
|
||||
RemoteTimeout model.Duration `yaml:"remote_timeout,omitempty"`
|
||||
Headers map[string]string `yaml:"headers,omitempty"`
|
||||
ReadRecent bool `yaml:"read_recent,omitempty"`
|
||||
Name string `yaml:"name,omitempty"`
|
||||
|
||||
// We cannot do proper Go type embedding below as the parser will then parse
|
||||
// values arbitrarily into the overflow maps of further-down types.
|
||||
HTTPClientConfig config.HTTPClientConfig `yaml:",inline"`
|
||||
|
||||
// RequiredMatchers is an optional list of equality matchers which have to
|
||||
// be present in a selector to query the remote read endpoint.
|
||||
RequiredMatchers model.LabelSet `yaml:"required_matchers,omitempty"`
|
||||
|
||||
// Whether to use the external labels as selectors for the remote read endpoint.
|
||||
FilterExternalLabels bool `yaml:"filter_external_labels,omitempty"`
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *RemoteReadConfig) SetDirectory(dir string) {
|
||||
c.HTTPClientConfig.SetDirectory(dir)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *RemoteReadConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultRemoteReadConfig
|
||||
type plain RemoteReadConfig
|
||||
if err := unmarshal((*plain)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.URL == nil {
|
||||
return errors.New("url for remote_read is empty")
|
||||
}
|
||||
if err := validateHeaders(c.Headers); err != nil {
|
||||
return err
|
||||
}
|
||||
// The UnmarshalYAML method of HTTPClientConfig is not being called because it's not a pointer.
|
||||
// We cannot make it a pointer as the parser panics for inlined pointer structs.
|
||||
// Thus we just do its validation here.
|
||||
return c.HTTPClientConfig.Validate()
|
||||
}
|
||||
267
vendor/github.com/prometheus/prometheus/discovery/README.md
generated
vendored
Normal file
267
vendor/github.com/prometheus/prometheus/discovery/README.md
generated
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
# Service Discovery
|
||||
|
||||
This directory contains the service discovery (SD) component of Prometheus.
|
||||
|
||||
## Design of a Prometheus SD
|
||||
|
||||
There are many requests to add new SDs to Prometheus, this section looks at
|
||||
what makes a good SD and covers some of the common implementation issues.
|
||||
|
||||
### Does this make sense as an SD?
|
||||
|
||||
The first question to be asked is does it make sense to add this particular
|
||||
SD? An SD mechanism should be reasonably well established, and at a minimum in
|
||||
use across multiple organizations. It should allow discovering of machines
|
||||
and/or services running somewhere. When exactly an SD is popular enough to
|
||||
justify being added to Prometheus natively is an open question.
|
||||
|
||||
Note: As part of lifting the past moratorium on new SD implementations it was
|
||||
agreed that, in addition to the existing requirements, new service discovery
|
||||
implementations will be required to have a committed maintainer with push access (i.e., on -team).
|
||||
|
||||
It should not be a brand new SD mechanism, or a variant of an established
|
||||
mechanism. We want to integrate Prometheus with the SD that's already there in
|
||||
your infrastructure, not invent yet more ways to do service discovery. We also
|
||||
do not add mechanisms to work around users lacking service discovery and/or
|
||||
configuration management infrastructure.
|
||||
|
||||
SDs that merely discover other applications running the same software (e.g.
|
||||
talk to one Kafka or Cassandra server to find the others) are not service
|
||||
discovery. In that case the SD you should be looking at is whatever decides
|
||||
that a machine is going to be a Kafka server, likely a machine database or
|
||||
configuration management system.
|
||||
|
||||
If something is particularly custom or unusual, `file_sd` is the generic
|
||||
mechanism provided for users to hook in. Generally with Prometheus we offer a
|
||||
single generic mechanism for things with infinite variations, rather than
|
||||
trying to support everything natively (see also, alertmanager webhook, remote
|
||||
read, remote write, node exporter textfile collector). For example anything
|
||||
that would involve talking to a relational database should use `file_sd`
|
||||
instead.
|
||||
|
||||
For configuration management systems like Chef, while they do have a
|
||||
database/API that'd in principle make sense to talk to for service discovery,
|
||||
the idiomatic approach is to use Chef's templating facilities to write out a
|
||||
file for use with `file_sd`.
|
||||
|
||||
|
||||
### Mapping from SD to Prometheus
|
||||
|
||||
The general principle with SD is to extract all the potentially useful
|
||||
information we can out of the SD, and let the user choose what they need of it
|
||||
using
|
||||
[relabelling](https://prometheus.io/docs/operating/configuration/#<relabel_config>).
|
||||
This information is generally termed metadata.
|
||||
|
||||
Metadata is exposed as a set of key/value pairs (labels) per target. The keys
|
||||
are prefixed with `__meta_<sdname>_<key>`, and there should also be an `__address__`
|
||||
label with the host:port of the target (preferably an IP address to avoid DNS
|
||||
lookups). No other labelnames should be exposed.
|
||||
|
||||
It is very common for initial pull requests for new SDs to include hardcoded
|
||||
assumptions that make sense for the author's setup. SD should be generic,
|
||||
any customisation should be handled via relabelling. There should be basically
|
||||
no business logic, filtering, or transformations of the data from the SD beyond
|
||||
that which is needed to fit it into the metadata data model.
|
||||
|
||||
Arrays (e.g. a list of tags) should be converted to a single label with the
|
||||
array values joined with a comma. Also prefix and suffix the value with a
|
||||
comma. So for example the array `[a, b, c]` would become `,a,b,c,`. As
|
||||
relabelling regexes are fully anchored, this makes it easier to write correct
|
||||
regexes against (`.*,a,.*` works no matter where `a` appears in the list). The
|
||||
canonical example of this is `__meta_consul_tags`.
|
||||
|
||||
Maps, hashes and other forms of key/value pairs should be all prefixed and
|
||||
exposed as labels. For example for EC2 tags, there would be
|
||||
`__meta_ec2_tag_Description=mydescription` for the Description tag. Labelnames
|
||||
may only contain `[_a-zA-Z0-9]`, sanitize by replacing with underscores as needed.
|
||||
|
||||
For targets with multiple potential ports, you can a) expose them as a list, b)
|
||||
if they're named expose them as a map or c) expose them each as their own
|
||||
target. Kubernetes SD takes the target per port approach. a) and b) can be
|
||||
combined.
|
||||
|
||||
For machine-like SDs (OpenStack, EC2, Kubernetes to some extent) there may
|
||||
be multiple network interfaces for a target. Thus far reporting the details
|
||||
of only the first/primary network interface has sufficed.
|
||||
|
||||
|
||||
### Other implementation considerations
|
||||
|
||||
SDs are intended to dump all possible targets. For example the optional use of
|
||||
EC2 service discovery would be to take the entire region's worth of EC2
|
||||
instances it provides and do everything needed in one `scrape_config`. For
|
||||
large deployments where you are only interested in a small proportion of the
|
||||
returned targets, this may cause performance issues. If this occurs it is
|
||||
acceptable to also offer filtering via whatever mechanisms the SD exposes. For
|
||||
EC2 that would be the `Filter` option on `DescribeInstances`. Keep in mind that
|
||||
this is a performance optimisation, it should be possible to do the same
|
||||
filtering using relabelling alone. As with SD generally, we do not invent new
|
||||
ways to filter targets (that is what relabelling is for), merely offer up
|
||||
whatever functionality the SD itself offers.
|
||||
|
||||
It is a general rule with Prometheus that all configuration comes from the
|
||||
configuration file. While the libraries you use to talk to the SD may also
|
||||
offer other mechanisms for providing configuration/authentication under the
|
||||
covers (EC2's use of environment variables being a prime example), using your SD
|
||||
mechanism should not require this. Put another way, your SD implementation
|
||||
should not read environment variables or files to obtain configuration.
|
||||
|
||||
Some SD mechanisms have rate limits that make them challenging to use. As an
|
||||
example we have unfortunately had to reject Amazon ECS service discovery due to
|
||||
the rate limits being so low that it would not be usable for anything beyond
|
||||
small setups.
|
||||
|
||||
If a system offers multiple distinct types of SD, select which is in use with a
|
||||
configuration option rather than returning them all from one mega SD that
|
||||
requires relabelling to select just the one you want. So far we have only seen
|
||||
this with Kubernetes. When a single SD with a selector vs. multiple distinct
|
||||
SDs makes sense is an open question.
|
||||
|
||||
If there is a failure while processing talking to the SD, abort rather than
|
||||
returning partial data. It is better to work from stale targets than partial
|
||||
or incorrect metadata.
|
||||
|
||||
The information obtained from service discovery is not considered sensitive
|
||||
security wise. Do not return secrets in metadata, anyone with access to
|
||||
the Prometheus server will be able to see them.
|
||||
|
||||
|
||||
## Writing an SD mechanism
|
||||
|
||||
### The SD interface
|
||||
|
||||
A Service Discovery (SD) mechanism has to discover targets and provide them to Prometheus. We expect similar targets to be grouped together, in the form of a [target group](https://pkg.go.dev/github.com/prometheus/prometheus/discovery/targetgroup#Group). The SD mechanism sends the targets down to prometheus as list of target groups.
|
||||
|
||||
An SD mechanism has to implement the `Discoverer` Interface:
|
||||
```go
|
||||
type Discoverer interface {
|
||||
Run(ctx context.Context, up chan<- []*targetgroup.Group)
|
||||
}
|
||||
```
|
||||
|
||||
Prometheus will call the `Run()` method on a provider to initialize the discovery mechanism. The mechanism will then send *all* the target groups into the channel.
|
||||
Now the mechanism will watch for changes. For each update it can send all target groups, or only changed and new target groups, down the channel. `Manager` will handle
|
||||
both cases.
|
||||
|
||||
For example if we had a discovery mechanism and it retrieves the following groups:
|
||||
|
||||
```go
|
||||
[]targetgroup.Group{
|
||||
{
|
||||
Targets: []model.LabelSet{
|
||||
{
|
||||
"__instance__": "10.11.150.1:7870",
|
||||
"hostname": "demo-target-1",
|
||||
"test": "simple-test",
|
||||
},
|
||||
{
|
||||
"__instance__": "10.11.150.4:7870",
|
||||
"hostname": "demo-target-2",
|
||||
"test": "simple-test",
|
||||
},
|
||||
},
|
||||
Labels: model.LabelSet{
|
||||
"job": "mysql",
|
||||
},
|
||||
"Source": "file1",
|
||||
},
|
||||
{
|
||||
Targets: []model.LabelSet{
|
||||
{
|
||||
"__instance__": "10.11.122.11:6001",
|
||||
"hostname": "demo-postgres-1",
|
||||
"test": "simple-test",
|
||||
},
|
||||
{
|
||||
"__instance__": "10.11.122.15:6001",
|
||||
"hostname": "demo-postgres-2",
|
||||
"test": "simple-test",
|
||||
},
|
||||
},
|
||||
Labels: model.LabelSet{
|
||||
"job": "postgres",
|
||||
},
|
||||
"Source": "file2",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Here there are two target groups one group with source `file1` and another with `file2`. The grouping is implementation specific and could even be one target per group. But, one has to make sure every target group sent by an SD instance should have a `Source` which is unique across all the target groups of that SD instance.
|
||||
|
||||
In this case, both the target groups are sent down the channel the first time `Run()` is called. Now, for an update, we need to send the whole _changed_ target group down the channel. i.e, if the target with `hostname: demo-postgres-2` goes away, we send:
|
||||
```go
|
||||
&targetgroup.Group{
|
||||
Targets: []model.LabelSet{
|
||||
{
|
||||
"__instance__": "10.11.122.11:6001",
|
||||
"hostname": "demo-postgres-1",
|
||||
"test": "simple-test",
|
||||
},
|
||||
},
|
||||
Labels: model.LabelSet{
|
||||
"job": "postgres",
|
||||
},
|
||||
"Source": "file2",
|
||||
}
|
||||
```
|
||||
down the channel.
|
||||
|
||||
If all the targets in a group go away, we need to send the target groups with empty `Targets` down the channel. i.e, if all targets with `job: postgres` go away, we send:
|
||||
```go
|
||||
&targetgroup.Group{
|
||||
Targets: nil,
|
||||
"Source": "file2",
|
||||
}
|
||||
```
|
||||
down the channel.
|
||||
|
||||
### The Config interface
|
||||
|
||||
Now that your service discovery mechanism is ready to discover targets, you must help
|
||||
Prometheus discover it. This is done by implementing the `discovery.Config` interface
|
||||
and registering it with `discovery.RegisterConfig` in an init function of your package.
|
||||
|
||||
```go
|
||||
type Config interface {
|
||||
// Name returns the name of the discovery mechanism.
|
||||
Name() string
|
||||
|
||||
// NewDiscoverer returns a Discoverer for the Config
|
||||
// with the given DiscovererOptions.
|
||||
NewDiscoverer(DiscovererOptions) (Discoverer, error)
|
||||
}
|
||||
|
||||
type DiscovererOptions struct {
|
||||
Logger log.Logger
|
||||
}
|
||||
```
|
||||
|
||||
The value returned by `Name()` should be short, descriptive, lowercase, and unique.
|
||||
It's used to tag the provided `Logger` and as the part of the YAML key for your SD
|
||||
mechanism's list of configs in `scrape_config` and `alertmanager_config`
|
||||
(e.g. `${NAME}_sd_configs`).
|
||||
|
||||
### New Service Discovery Check List
|
||||
|
||||
Here are some non-obvious parts of adding service discoveries that need to be verified:
|
||||
|
||||
- Validate that discovery configs can be DeepEqualled by adding them to
|
||||
`config/testdata/conf.good.yml` and to the associated tests.
|
||||
|
||||
- If the config contains file paths directly or indirectly (e.g. with a TLSConfig or
|
||||
HTTPClientConfig field), then it must implement `config.DirectorySetter`.
|
||||
|
||||
- Import your SD package from `prometheus/discovery/install`. The install package is
|
||||
imported from `main` to register all builtin SD mechanisms.
|
||||
|
||||
- List the service discovery in both `<scrape_config>` and
|
||||
`<alertmanager_config>` in `docs/configuration/configuration.md`.
|
||||
|
||||
<!-- TODO: Add best-practices -->
|
||||
|
||||
### Examples of Service Discovery pull requests
|
||||
|
||||
The examples given might become out of date but should give a good impression about the areas touched by a new service discovery.
|
||||
|
||||
- [Eureka](https://github.com/prometheus/prometheus/pull/3369)
|
||||
121
vendor/github.com/prometheus/prometheus/discovery/discovery.go
generated
vendored
Normal file
121
vendor/github.com/prometheus/prometheus/discovery/discovery.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
// Copyright 2020 The Prometheus Authors
|
||||
// Licensed 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 discovery
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/prometheus/common/config"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
)
|
||||
|
||||
// Discoverer provides information about target groups. It maintains a set
|
||||
// of sources from which TargetGroups can originate. Whenever a discovery provider
|
||||
// detects a potential change, it sends the TargetGroup through its channel.
|
||||
//
|
||||
// Discoverer does not know if an actual change happened.
|
||||
// It does guarantee that it sends the new TargetGroup whenever a change happens.
|
||||
//
|
||||
// Discoverers should initially send a full set of all discoverable TargetGroups.
|
||||
type Discoverer interface {
|
||||
// Run hands a channel to the discovery provider (Consul, DNS, etc.) through which
|
||||
// it can send updated target groups. It must return when the context is canceled.
|
||||
// It should not close the update channel on returning.
|
||||
Run(ctx context.Context, up chan<- []*targetgroup.Group)
|
||||
}
|
||||
|
||||
// DiscovererOptions provides options for a Discoverer.
|
||||
type DiscovererOptions struct {
|
||||
Logger log.Logger
|
||||
|
||||
// Extra HTTP client options to expose to Discoverers. This field may be
|
||||
// ignored; Discoverer implementations must opt-in to reading it.
|
||||
HTTPClientOptions []config.HTTPClientOption
|
||||
}
|
||||
|
||||
// A Config provides the configuration and constructor for a Discoverer.
|
||||
type Config interface {
|
||||
// Name returns the name of the discovery mechanism.
|
||||
Name() string
|
||||
|
||||
// NewDiscoverer returns a Discoverer for the Config
|
||||
// with the given DiscovererOptions.
|
||||
NewDiscoverer(DiscovererOptions) (Discoverer, error)
|
||||
}
|
||||
|
||||
// Configs is a slice of Config values that uses custom YAML marshaling and unmarshaling
|
||||
// to represent itself as a mapping of the Config values grouped by their types.
|
||||
type Configs []Config
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *Configs) SetDirectory(dir string) {
|
||||
for _, c := range *c {
|
||||
if v, ok := c.(config.DirectorySetter); ok {
|
||||
v.SetDirectory(dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaler.
|
||||
func (c *Configs) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
cfgTyp := getConfigType(configsType)
|
||||
cfgPtr := reflect.New(cfgTyp)
|
||||
cfgVal := cfgPtr.Elem()
|
||||
|
||||
if err := unmarshal(cfgPtr.Interface()); err != nil {
|
||||
return replaceYAMLTypeError(err, cfgTyp, configsType)
|
||||
}
|
||||
|
||||
var err error
|
||||
*c, err = readConfigs(cfgVal, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalYAML implements yaml.Marshaler.
|
||||
func (c Configs) MarshalYAML() (interface{}, error) {
|
||||
cfgTyp := getConfigType(configsType)
|
||||
cfgPtr := reflect.New(cfgTyp)
|
||||
cfgVal := cfgPtr.Elem()
|
||||
|
||||
if err := writeConfigs(cfgVal, c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cfgPtr.Interface(), nil
|
||||
}
|
||||
|
||||
// A StaticConfig is a Config that provides a static list of targets.
|
||||
type StaticConfig []*targetgroup.Group
|
||||
|
||||
// Name returns the name of the service discovery mechanism.
|
||||
func (StaticConfig) Name() string { return "static" }
|
||||
|
||||
// NewDiscoverer returns a Discoverer for the Config.
|
||||
func (c StaticConfig) NewDiscoverer(DiscovererOptions) (Discoverer, error) {
|
||||
return staticDiscoverer(c), nil
|
||||
}
|
||||
|
||||
type staticDiscoverer []*targetgroup.Group
|
||||
|
||||
func (c staticDiscoverer) Run(ctx context.Context, up chan<- []*targetgroup.Group) {
|
||||
// TODO: existing implementation closes up chan, but documentation explicitly forbids it...?
|
||||
defer close(up)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case up <- c:
|
||||
}
|
||||
}
|
||||
478
vendor/github.com/prometheus/prometheus/discovery/manager.go
generated
vendored
Normal file
478
vendor/github.com/prometheus/prometheus/discovery/manager.go
generated
vendored
Normal file
@@ -0,0 +1,478 @@
|
||||
// Copyright 2016 The Prometheus Authors
|
||||
// Licensed 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 discovery
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/config"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
)
|
||||
|
||||
var (
|
||||
failedConfigs = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "prometheus_sd_failed_configs",
|
||||
Help: "Current number of service discovery configurations that failed to load.",
|
||||
},
|
||||
[]string{"name"},
|
||||
)
|
||||
discoveredTargets = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "prometheus_sd_discovered_targets",
|
||||
Help: "Current number of discovered targets.",
|
||||
},
|
||||
[]string{"name", "config"},
|
||||
)
|
||||
receivedUpdates = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "prometheus_sd_received_updates_total",
|
||||
Help: "Total number of update events received from the SD providers.",
|
||||
},
|
||||
[]string{"name"},
|
||||
)
|
||||
delayedUpdates = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "prometheus_sd_updates_delayed_total",
|
||||
Help: "Total number of update events that couldn't be sent immediately.",
|
||||
},
|
||||
[]string{"name"},
|
||||
)
|
||||
sentUpdates = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "prometheus_sd_updates_total",
|
||||
Help: "Total number of update events sent to the SD consumers.",
|
||||
},
|
||||
[]string{"name"},
|
||||
)
|
||||
)
|
||||
|
||||
func RegisterMetrics() {
|
||||
prometheus.MustRegister(failedConfigs, discoveredTargets, receivedUpdates, delayedUpdates, sentUpdates)
|
||||
}
|
||||
|
||||
type poolKey struct {
|
||||
setName string
|
||||
provider string
|
||||
}
|
||||
|
||||
// Provider holds a Discoverer instance, its configuration, cancel func and its subscribers.
|
||||
type Provider struct {
|
||||
name string
|
||||
d Discoverer
|
||||
config interface{}
|
||||
|
||||
cancel context.CancelFunc
|
||||
// done should be called after cleaning up resources associated with cancelled provider.
|
||||
done func()
|
||||
|
||||
mu sync.RWMutex
|
||||
subs map[string]struct{}
|
||||
|
||||
// newSubs is used to temporary store subs to be used upon config reload completion.
|
||||
newSubs map[string]struct{}
|
||||
}
|
||||
|
||||
// Discoverer return the Discoverer of the provider
|
||||
func (p *Provider) Discoverer() Discoverer {
|
||||
return p.d
|
||||
}
|
||||
|
||||
// IsStarted return true if Discoverer is started.
|
||||
func (p *Provider) IsStarted() bool {
|
||||
return p.cancel != nil
|
||||
}
|
||||
|
||||
func (p *Provider) Config() interface{} {
|
||||
return p.config
|
||||
}
|
||||
|
||||
// NewManager is the Discovery Manager constructor.
|
||||
func NewManager(ctx context.Context, logger log.Logger, options ...func(*Manager)) *Manager {
|
||||
if logger == nil {
|
||||
logger = log.NewNopLogger()
|
||||
}
|
||||
mgr := &Manager{
|
||||
logger: logger,
|
||||
syncCh: make(chan map[string][]*targetgroup.Group),
|
||||
targets: make(map[poolKey]map[string]*targetgroup.Group),
|
||||
ctx: ctx,
|
||||
updatert: 5 * time.Second,
|
||||
triggerSend: make(chan struct{}, 1),
|
||||
}
|
||||
for _, option := range options {
|
||||
option(mgr)
|
||||
}
|
||||
return mgr
|
||||
}
|
||||
|
||||
// Name sets the name of the manager.
|
||||
func Name(n string) func(*Manager) {
|
||||
return func(m *Manager) {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
m.name = n
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPClientOptions sets the list of HTTP client options to expose to
|
||||
// Discoverers. It is up to Discoverers to choose to use the options provided.
|
||||
func HTTPClientOptions(opts ...config.HTTPClientOption) func(*Manager) {
|
||||
return func(m *Manager) {
|
||||
m.httpOpts = opts
|
||||
}
|
||||
}
|
||||
|
||||
// Manager maintains a set of discovery providers and sends each update to a map channel.
|
||||
// Targets are grouped by the target set name.
|
||||
type Manager struct {
|
||||
logger log.Logger
|
||||
name string
|
||||
httpOpts []config.HTTPClientOption
|
||||
mtx sync.RWMutex
|
||||
ctx context.Context
|
||||
|
||||
// Some Discoverers(e.g. k8s) send only the updates for a given target group,
|
||||
// so we use map[tg.Source]*targetgroup.Group to know which group to update.
|
||||
targets map[poolKey]map[string]*targetgroup.Group
|
||||
targetsMtx sync.Mutex
|
||||
|
||||
// providers keeps track of SD providers.
|
||||
providers []*Provider
|
||||
// The sync channel sends the updates as a map where the key is the job value from the scrape config.
|
||||
syncCh chan map[string][]*targetgroup.Group
|
||||
|
||||
// How long to wait before sending updates to the channel. The variable
|
||||
// should only be modified in unit tests.
|
||||
updatert time.Duration
|
||||
|
||||
// The triggerSend channel signals to the Manager that new updates have been received from providers.
|
||||
triggerSend chan struct{}
|
||||
|
||||
// lastProvider counts providers registered during Manager's lifetime.
|
||||
lastProvider uint
|
||||
}
|
||||
|
||||
// Providers returns the currently configured SD providers.
|
||||
func (m *Manager) Providers() []*Provider {
|
||||
return m.providers
|
||||
}
|
||||
|
||||
// Run starts the background processing.
|
||||
func (m *Manager) Run() error {
|
||||
go m.sender()
|
||||
for range m.ctx.Done() {
|
||||
m.cancelDiscoverers()
|
||||
return m.ctx.Err()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SyncCh returns a read only channel used by all the clients to receive target updates.
|
||||
func (m *Manager) SyncCh() <-chan map[string][]*targetgroup.Group {
|
||||
return m.syncCh
|
||||
}
|
||||
|
||||
// ApplyConfig checks if discovery provider with supplied config is already running and keeps them as is.
|
||||
// Remaining providers are then stopped and new required providers are started using the provided config.
|
||||
func (m *Manager) ApplyConfig(cfg map[string]Configs) error {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
|
||||
var failedCount int
|
||||
for name, scfg := range cfg {
|
||||
failedCount += m.registerProviders(scfg, name)
|
||||
}
|
||||
failedConfigs.WithLabelValues(m.name).Set(float64(failedCount))
|
||||
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
// keep shows if we keep any providers after reload.
|
||||
keep bool
|
||||
newProviders []*Provider
|
||||
)
|
||||
for _, prov := range m.providers {
|
||||
// Cancel obsolete providers.
|
||||
if len(prov.newSubs) == 0 {
|
||||
wg.Add(1)
|
||||
prov.done = func() {
|
||||
wg.Done()
|
||||
}
|
||||
prov.cancel()
|
||||
continue
|
||||
}
|
||||
newProviders = append(newProviders, prov)
|
||||
// refTargets keeps reference targets used to populate new subs' targets
|
||||
var refTargets map[string]*targetgroup.Group
|
||||
prov.mu.Lock()
|
||||
|
||||
m.targetsMtx.Lock()
|
||||
for s := range prov.subs {
|
||||
keep = true
|
||||
refTargets = m.targets[poolKey{s, prov.name}]
|
||||
// Remove obsolete subs' targets.
|
||||
if _, ok := prov.newSubs[s]; !ok {
|
||||
delete(m.targets, poolKey{s, prov.name})
|
||||
discoveredTargets.DeleteLabelValues(m.name, s)
|
||||
}
|
||||
}
|
||||
// Set metrics and targets for new subs.
|
||||
for s := range prov.newSubs {
|
||||
if _, ok := prov.subs[s]; !ok {
|
||||
discoveredTargets.WithLabelValues(m.name, s).Set(0)
|
||||
}
|
||||
if l := len(refTargets); l > 0 {
|
||||
m.targets[poolKey{s, prov.name}] = make(map[string]*targetgroup.Group, l)
|
||||
for k, v := range refTargets {
|
||||
m.targets[poolKey{s, prov.name}][k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
m.targetsMtx.Unlock()
|
||||
|
||||
prov.subs = prov.newSubs
|
||||
prov.newSubs = map[string]struct{}{}
|
||||
prov.mu.Unlock()
|
||||
if !prov.IsStarted() {
|
||||
m.startProvider(m.ctx, prov)
|
||||
}
|
||||
}
|
||||
// Currently downstream managers expect full target state upon config reload, so we must oblige.
|
||||
// While startProvider does pull the trigger, it may take some time to do so, therefore
|
||||
// we pull the trigger as soon as possible so that downstream managers can populate their state.
|
||||
// See https://github.com/prometheus/prometheus/pull/8639 for details.
|
||||
if keep {
|
||||
select {
|
||||
case m.triggerSend <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
m.providers = newProviders
|
||||
wg.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartCustomProvider is used for sdtool. Only use this if you know what you're doing.
|
||||
func (m *Manager) StartCustomProvider(ctx context.Context, name string, worker Discoverer) {
|
||||
p := &Provider{
|
||||
name: name,
|
||||
d: worker,
|
||||
subs: map[string]struct{}{
|
||||
name: {},
|
||||
},
|
||||
}
|
||||
m.providers = append(m.providers, p)
|
||||
m.startProvider(ctx, p)
|
||||
}
|
||||
|
||||
func (m *Manager) startProvider(ctx context.Context, p *Provider) {
|
||||
level.Debug(m.logger).Log("msg", "Starting provider", "provider", p.name, "subs", fmt.Sprintf("%v", p.subs))
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
updates := make(chan []*targetgroup.Group)
|
||||
|
||||
p.cancel = cancel
|
||||
|
||||
go p.d.Run(ctx, updates)
|
||||
go m.updater(ctx, p, updates)
|
||||
}
|
||||
|
||||
// cleaner cleans resources associated with provider.
|
||||
func (m *Manager) cleaner(p *Provider) {
|
||||
m.targetsMtx.Lock()
|
||||
p.mu.RLock()
|
||||
for s := range p.subs {
|
||||
delete(m.targets, poolKey{s, p.name})
|
||||
}
|
||||
p.mu.RUnlock()
|
||||
m.targetsMtx.Unlock()
|
||||
if p.done != nil {
|
||||
p.done()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) updater(ctx context.Context, p *Provider, updates chan []*targetgroup.Group) {
|
||||
// Ensure targets from this provider are cleaned up.
|
||||
defer m.cleaner(p)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case tgs, ok := <-updates:
|
||||
receivedUpdates.WithLabelValues(m.name).Inc()
|
||||
if !ok {
|
||||
level.Debug(m.logger).Log("msg", "Discoverer channel closed", "provider", p.name)
|
||||
// Wait for provider cancellation to ensure targets are cleaned up when expected.
|
||||
<-ctx.Done()
|
||||
return
|
||||
}
|
||||
|
||||
p.mu.RLock()
|
||||
for s := range p.subs {
|
||||
m.updateGroup(poolKey{setName: s, provider: p.name}, tgs)
|
||||
}
|
||||
p.mu.RUnlock()
|
||||
|
||||
select {
|
||||
case m.triggerSend <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) sender() {
|
||||
ticker := time.NewTicker(m.updatert)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-m.ctx.Done():
|
||||
return
|
||||
case <-ticker.C: // Some discoverers send updates too often, so we throttle these with the ticker.
|
||||
select {
|
||||
case <-m.triggerSend:
|
||||
sentUpdates.WithLabelValues(m.name).Inc()
|
||||
select {
|
||||
case m.syncCh <- m.allGroups():
|
||||
default:
|
||||
delayedUpdates.WithLabelValues(m.name).Inc()
|
||||
level.Debug(m.logger).Log("msg", "Discovery receiver's channel was full so will retry the next cycle")
|
||||
select {
|
||||
case m.triggerSend <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) cancelDiscoverers() {
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
for _, p := range m.providers {
|
||||
if p.cancel != nil {
|
||||
p.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) updateGroup(poolKey poolKey, tgs []*targetgroup.Group) {
|
||||
m.targetsMtx.Lock()
|
||||
defer m.targetsMtx.Unlock()
|
||||
|
||||
if _, ok := m.targets[poolKey]; !ok {
|
||||
m.targets[poolKey] = make(map[string]*targetgroup.Group)
|
||||
}
|
||||
for _, tg := range tgs {
|
||||
if tg != nil { // Some Discoverers send nil target group so need to check for it to avoid panics.
|
||||
m.targets[poolKey][tg.Source] = tg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) allGroups() map[string][]*targetgroup.Group {
|
||||
tSets := map[string][]*targetgroup.Group{}
|
||||
n := map[string]int{}
|
||||
|
||||
m.targetsMtx.Lock()
|
||||
defer m.targetsMtx.Unlock()
|
||||
for pkey, tsets := range m.targets {
|
||||
for _, tg := range tsets {
|
||||
// Even if the target group 'tg' is empty we still need to send it to the 'Scrape manager'
|
||||
// to signal that it needs to stop all scrape loops for this target set.
|
||||
tSets[pkey.setName] = append(tSets[pkey.setName], tg)
|
||||
n[pkey.setName] += len(tg.Targets)
|
||||
}
|
||||
}
|
||||
for setName, v := range n {
|
||||
discoveredTargets.WithLabelValues(m.name, setName).Set(float64(v))
|
||||
}
|
||||
return tSets
|
||||
}
|
||||
|
||||
// registerProviders returns a number of failed SD config.
|
||||
func (m *Manager) registerProviders(cfgs Configs, setName string) int {
|
||||
var (
|
||||
failed int
|
||||
added bool
|
||||
)
|
||||
add := func(cfg Config) {
|
||||
for _, p := range m.providers {
|
||||
if reflect.DeepEqual(cfg, p.config) {
|
||||
p.newSubs[setName] = struct{}{}
|
||||
added = true
|
||||
return
|
||||
}
|
||||
}
|
||||
typ := cfg.Name()
|
||||
d, err := cfg.NewDiscoverer(DiscovererOptions{
|
||||
Logger: log.With(m.logger, "discovery", typ, "config", setName),
|
||||
HTTPClientOptions: m.httpOpts,
|
||||
})
|
||||
if err != nil {
|
||||
level.Error(m.logger).Log("msg", "Cannot create service discovery", "err", err, "type", typ, "config", setName)
|
||||
failed++
|
||||
return
|
||||
}
|
||||
m.providers = append(m.providers, &Provider{
|
||||
name: fmt.Sprintf("%s/%d", typ, m.lastProvider),
|
||||
d: d,
|
||||
config: cfg,
|
||||
newSubs: map[string]struct{}{
|
||||
setName: {},
|
||||
},
|
||||
})
|
||||
m.lastProvider++
|
||||
added = true
|
||||
}
|
||||
for _, cfg := range cfgs {
|
||||
add(cfg)
|
||||
}
|
||||
if !added {
|
||||
// Add an empty target group to force the refresh of the corresponding
|
||||
// scrape pool and to notify the receiver that this target set has no
|
||||
// current targets.
|
||||
// It can happen because the combined set of SD configurations is empty
|
||||
// or because we fail to instantiate all the SD configurations.
|
||||
add(StaticConfig{{}})
|
||||
}
|
||||
return failed
|
||||
}
|
||||
|
||||
// StaticProvider holds a list of target groups that never change.
|
||||
type StaticProvider struct {
|
||||
TargetGroups []*targetgroup.Group
|
||||
}
|
||||
|
||||
// Run implements the Worker interface.
|
||||
func (sd *StaticProvider) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
|
||||
// We still have to consider that the consumer exits right away in which case
|
||||
// the context will be canceled.
|
||||
select {
|
||||
case ch <- sd.TargetGroups:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
close(ch)
|
||||
}
|
||||
260
vendor/github.com/prometheus/prometheus/discovery/registry.go
generated
vendored
Normal file
260
vendor/github.com/prometheus/prometheus/discovery/registry.go
generated
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
// Copyright 2020 The Prometheus Authors
|
||||
// Licensed 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 discovery
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
)
|
||||
|
||||
const (
|
||||
configFieldPrefix = "AUTO_DISCOVERY_"
|
||||
staticConfigsKey = "static_configs"
|
||||
staticConfigsFieldName = configFieldPrefix + staticConfigsKey
|
||||
)
|
||||
|
||||
var (
|
||||
configNames = make(map[string]Config)
|
||||
configFieldNames = make(map[reflect.Type]string)
|
||||
configFields []reflect.StructField
|
||||
|
||||
configTypesMu sync.Mutex
|
||||
configTypes = make(map[reflect.Type]reflect.Type)
|
||||
|
||||
emptyStructType = reflect.TypeOf(struct{}{})
|
||||
configsType = reflect.TypeOf(Configs{})
|
||||
)
|
||||
|
||||
// RegisterConfig registers the given Config type for YAML marshaling and unmarshaling.
|
||||
func RegisterConfig(config Config) {
|
||||
registerConfig(config.Name()+"_sd_configs", reflect.TypeOf(config), config)
|
||||
}
|
||||
|
||||
func init() {
|
||||
// N.B.: static_configs is the only Config type implemented by default.
|
||||
// All other types are registered at init by their implementing packages.
|
||||
elemTyp := reflect.TypeOf(&targetgroup.Group{})
|
||||
registerConfig(staticConfigsKey, elemTyp, StaticConfig{})
|
||||
}
|
||||
|
||||
func registerConfig(yamlKey string, elemType reflect.Type, config Config) {
|
||||
name := config.Name()
|
||||
if _, ok := configNames[name]; ok {
|
||||
panic(fmt.Sprintf("discovery: Config named %q is already registered", name))
|
||||
}
|
||||
configNames[name] = config
|
||||
|
||||
fieldName := configFieldPrefix + yamlKey // Field must be exported.
|
||||
configFieldNames[elemType] = fieldName
|
||||
|
||||
// Insert fields in sorted order.
|
||||
i := sort.Search(len(configFields), func(k int) bool {
|
||||
return fieldName < configFields[k].Name
|
||||
})
|
||||
configFields = append(configFields, reflect.StructField{}) // Add empty field at end.
|
||||
copy(configFields[i+1:], configFields[i:]) // Shift fields to the right.
|
||||
configFields[i] = reflect.StructField{ // Write new field in place.
|
||||
Name: fieldName,
|
||||
Type: reflect.SliceOf(elemType),
|
||||
Tag: reflect.StructTag(`yaml:"` + yamlKey + `,omitempty"`),
|
||||
}
|
||||
}
|
||||
|
||||
func getConfigType(out reflect.Type) reflect.Type {
|
||||
configTypesMu.Lock()
|
||||
defer configTypesMu.Unlock()
|
||||
if typ, ok := configTypes[out]; ok {
|
||||
return typ
|
||||
}
|
||||
// Initial exported fields map one-to-one.
|
||||
var fields []reflect.StructField
|
||||
for i, n := 0, out.NumField(); i < n; i++ {
|
||||
switch field := out.Field(i); {
|
||||
case field.PkgPath == "" && field.Type != configsType:
|
||||
fields = append(fields, field)
|
||||
default:
|
||||
fields = append(fields, reflect.StructField{
|
||||
Name: "_" + field.Name, // Field must be unexported.
|
||||
PkgPath: out.PkgPath(),
|
||||
Type: emptyStructType,
|
||||
})
|
||||
}
|
||||
}
|
||||
// Append extra config fields on the end.
|
||||
fields = append(fields, configFields...)
|
||||
typ := reflect.StructOf(fields)
|
||||
configTypes[out] = typ
|
||||
return typ
|
||||
}
|
||||
|
||||
// UnmarshalYAMLWithInlineConfigs helps implement yaml.Unmarshal for structs
|
||||
// that have a Configs field that should be inlined.
|
||||
func UnmarshalYAMLWithInlineConfigs(out interface{}, unmarshal func(interface{}) error) error {
|
||||
outVal := reflect.ValueOf(out)
|
||||
if outVal.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("discovery: can only unmarshal into a struct pointer: %T", out)
|
||||
}
|
||||
outVal = outVal.Elem()
|
||||
if outVal.Kind() != reflect.Struct {
|
||||
return fmt.Errorf("discovery: can only unmarshal into a struct pointer: %T", out)
|
||||
}
|
||||
outTyp := outVal.Type()
|
||||
|
||||
cfgTyp := getConfigType(outTyp)
|
||||
cfgPtr := reflect.New(cfgTyp)
|
||||
cfgVal := cfgPtr.Elem()
|
||||
|
||||
// Copy shared fields (defaults) to dynamic value.
|
||||
var configs *Configs
|
||||
for i, n := 0, outVal.NumField(); i < n; i++ {
|
||||
if outTyp.Field(i).Type == configsType {
|
||||
configs = outVal.Field(i).Addr().Interface().(*Configs)
|
||||
continue
|
||||
}
|
||||
if cfgTyp.Field(i).PkgPath != "" {
|
||||
continue // Field is unexported: ignore.
|
||||
}
|
||||
cfgVal.Field(i).Set(outVal.Field(i))
|
||||
}
|
||||
if configs == nil {
|
||||
return fmt.Errorf("discovery: Configs field not found in type: %T", out)
|
||||
}
|
||||
|
||||
// Unmarshal into dynamic value.
|
||||
if err := unmarshal(cfgPtr.Interface()); err != nil {
|
||||
return replaceYAMLTypeError(err, cfgTyp, outTyp)
|
||||
}
|
||||
|
||||
// Copy shared fields from dynamic value.
|
||||
for i, n := 0, outVal.NumField(); i < n; i++ {
|
||||
if cfgTyp.Field(i).PkgPath != "" {
|
||||
continue // Field is unexported: ignore.
|
||||
}
|
||||
outVal.Field(i).Set(cfgVal.Field(i))
|
||||
}
|
||||
|
||||
var err error
|
||||
*configs, err = readConfigs(cfgVal, outVal.NumField())
|
||||
return err
|
||||
}
|
||||
|
||||
func readConfigs(structVal reflect.Value, startField int) (Configs, error) {
|
||||
var (
|
||||
configs Configs
|
||||
targets []*targetgroup.Group
|
||||
)
|
||||
for i, n := startField, structVal.NumField(); i < n; i++ {
|
||||
field := structVal.Field(i)
|
||||
if field.Kind() != reflect.Slice {
|
||||
panic("discovery: internal error: field is not a slice")
|
||||
}
|
||||
for k := 0; k < field.Len(); k++ {
|
||||
val := field.Index(k)
|
||||
if val.IsZero() || (val.Kind() == reflect.Ptr && val.Elem().IsZero()) {
|
||||
key := configFieldNames[field.Type().Elem()]
|
||||
key = strings.TrimPrefix(key, configFieldPrefix)
|
||||
return nil, fmt.Errorf("empty or null section in %s", key)
|
||||
}
|
||||
switch c := val.Interface().(type) {
|
||||
case *targetgroup.Group:
|
||||
// Add index to the static config target groups for unique identification
|
||||
// within scrape pool.
|
||||
c.Source = strconv.Itoa(len(targets))
|
||||
// Coalesce multiple static configs into a single static config.
|
||||
targets = append(targets, c)
|
||||
case Config:
|
||||
configs = append(configs, c)
|
||||
default:
|
||||
panic("discovery: internal error: slice element is not a Config")
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(targets) > 0 {
|
||||
configs = append(configs, StaticConfig(targets))
|
||||
}
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
// MarshalYAMLWithInlineConfigs helps implement yaml.Marshal for structs
|
||||
// that have a Configs field that should be inlined.
|
||||
func MarshalYAMLWithInlineConfigs(in interface{}) (interface{}, error) {
|
||||
inVal := reflect.ValueOf(in)
|
||||
for inVal.Kind() == reflect.Ptr {
|
||||
inVal = inVal.Elem()
|
||||
}
|
||||
inTyp := inVal.Type()
|
||||
|
||||
cfgTyp := getConfigType(inTyp)
|
||||
cfgPtr := reflect.New(cfgTyp)
|
||||
cfgVal := cfgPtr.Elem()
|
||||
|
||||
// Copy shared fields to dynamic value.
|
||||
var configs *Configs
|
||||
for i, n := 0, inTyp.NumField(); i < n; i++ {
|
||||
if inTyp.Field(i).Type == configsType {
|
||||
configs = inVal.Field(i).Addr().Interface().(*Configs)
|
||||
}
|
||||
if cfgTyp.Field(i).PkgPath != "" {
|
||||
continue // Field is unexported: ignore.
|
||||
}
|
||||
cfgVal.Field(i).Set(inVal.Field(i))
|
||||
}
|
||||
if configs == nil {
|
||||
return nil, fmt.Errorf("discovery: Configs field not found in type: %T", in)
|
||||
}
|
||||
|
||||
if err := writeConfigs(cfgVal, *configs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cfgPtr.Interface(), nil
|
||||
}
|
||||
|
||||
func writeConfigs(structVal reflect.Value, configs Configs) error {
|
||||
targets := structVal.FieldByName(staticConfigsFieldName).Addr().Interface().(*[]*targetgroup.Group)
|
||||
for _, c := range configs {
|
||||
if sc, ok := c.(StaticConfig); ok {
|
||||
*targets = append(*targets, sc...)
|
||||
continue
|
||||
}
|
||||
fieldName, ok := configFieldNames[reflect.TypeOf(c)]
|
||||
if !ok {
|
||||
return fmt.Errorf("discovery: cannot marshal unregistered Config type: %T", c)
|
||||
}
|
||||
field := structVal.FieldByName(fieldName)
|
||||
field.Set(reflect.Append(field, reflect.ValueOf(c)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func replaceYAMLTypeError(err error, oldTyp, newTyp reflect.Type) error {
|
||||
var e *yaml.TypeError
|
||||
if errors.As(err, &e) {
|
||||
oldStr := oldTyp.String()
|
||||
newStr := newTyp.String()
|
||||
for i, s := range e.Errors {
|
||||
e.Errors[i] = strings.Replace(s, oldStr, newStr, -1)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
108
vendor/github.com/prometheus/prometheus/discovery/targetgroup/targetgroup.go
generated
vendored
Normal file
108
vendor/github.com/prometheus/prometheus/discovery/targetgroup/targetgroup.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright 2013 The Prometheus Authors
|
||||
// Licensed 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 targetgroup
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
// Group is a set of targets with a common label set(production , test, staging etc.).
|
||||
type Group struct {
|
||||
// Targets is a list of targets identified by a label set. Each target is
|
||||
// uniquely identifiable in the group by its address label.
|
||||
Targets []model.LabelSet
|
||||
// Labels is a set of labels that is common across all targets in the group.
|
||||
Labels model.LabelSet
|
||||
|
||||
// Source is an identifier that describes a group of targets.
|
||||
Source string
|
||||
}
|
||||
|
||||
func (tg Group) String() string {
|
||||
return tg.Source
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (tg *Group) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
g := struct {
|
||||
Targets []string `yaml:"targets"`
|
||||
Labels model.LabelSet `yaml:"labels"`
|
||||
}{}
|
||||
if err := unmarshal(&g); err != nil {
|
||||
return err
|
||||
}
|
||||
tg.Targets = make([]model.LabelSet, 0, len(g.Targets))
|
||||
for _, t := range g.Targets {
|
||||
tg.Targets = append(tg.Targets, model.LabelSet{
|
||||
model.AddressLabel: model.LabelValue(t),
|
||||
})
|
||||
}
|
||||
tg.Labels = g.Labels
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalYAML implements the yaml.Marshaler interface.
|
||||
func (tg Group) MarshalYAML() (interface{}, error) {
|
||||
g := &struct {
|
||||
Targets []string `yaml:"targets"`
|
||||
Labels model.LabelSet `yaml:"labels,omitempty"`
|
||||
}{
|
||||
Targets: make([]string, 0, len(tg.Targets)),
|
||||
Labels: tg.Labels,
|
||||
}
|
||||
for _, t := range tg.Targets {
|
||||
g.Targets = append(g.Targets, string(t[model.AddressLabel]))
|
||||
}
|
||||
return g, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (tg *Group) UnmarshalJSON(b []byte) error {
|
||||
g := struct {
|
||||
Targets []string `json:"targets"`
|
||||
Labels model.LabelSet `json:"labels"`
|
||||
}{}
|
||||
|
||||
dec := json.NewDecoder(bytes.NewReader(b))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&g); err != nil {
|
||||
return err
|
||||
}
|
||||
tg.Targets = make([]model.LabelSet, 0, len(g.Targets))
|
||||
for _, t := range g.Targets {
|
||||
tg.Targets = append(tg.Targets, model.LabelSet{
|
||||
model.AddressLabel: model.LabelValue(t),
|
||||
})
|
||||
}
|
||||
tg.Labels = g.Labels
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (tg Group) MarshalJSON() ([]byte, error) {
|
||||
g := &struct {
|
||||
Targets []string `json:"targets"`
|
||||
Labels model.LabelSet `json:"labels,omitempty"`
|
||||
}{
|
||||
Targets: make([]string, 0, len(tg.Targets)),
|
||||
Labels: tg.Labels,
|
||||
}
|
||||
for _, t := range tg.Targets {
|
||||
g.Targets = append(g.Targets, string(t[model.AddressLabel]))
|
||||
}
|
||||
return json.Marshal(g)
|
||||
}
|
||||
50
vendor/github.com/prometheus/prometheus/model/exemplar/exemplar.go
generated
vendored
Normal file
50
vendor/github.com/prometheus/prometheus/model/exemplar/exemplar.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright 2019 The Prometheus Authors
|
||||
// Licensed 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 exemplar
|
||||
|
||||
import "github.com/prometheus/prometheus/model/labels"
|
||||
|
||||
// The combined length of the label names and values of an Exemplar's LabelSet MUST NOT exceed 128 UTF-8 characters
|
||||
// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#exemplars
|
||||
const ExemplarMaxLabelSetLength = 128
|
||||
|
||||
// Exemplar is additional information associated with a time series.
|
||||
type Exemplar struct {
|
||||
Labels labels.Labels `json:"labels"`
|
||||
Value float64 `json:"value"`
|
||||
Ts int64 `json:"timestamp"`
|
||||
HasTs bool
|
||||
}
|
||||
|
||||
type QueryResult struct {
|
||||
SeriesLabels labels.Labels `json:"seriesLabels"`
|
||||
Exemplars []Exemplar `json:"exemplars"`
|
||||
}
|
||||
|
||||
// Equals compares if the exemplar e is the same as e2. Note that if HasTs is false for
|
||||
// both exemplars then the timestamps will be ignored for the comparison. This can come up
|
||||
// when an exemplar is exported without it's own timestamp, in which case the scrape timestamp
|
||||
// is assigned to the Ts field. However we still want to treat the same exemplar, scraped without
|
||||
// an exported timestamp, as a duplicate of itself for each subsequent scrape.
|
||||
func (e Exemplar) Equals(e2 Exemplar) bool {
|
||||
if !labels.Equal(e.Labels, e2.Labels) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (e.HasTs || e2.HasTs) && e.Ts != e2.Ts {
|
||||
return false
|
||||
}
|
||||
|
||||
return e.Value == e2.Value
|
||||
}
|
||||
904
vendor/github.com/prometheus/prometheus/model/histogram/float_histogram.go
generated
vendored
Normal file
904
vendor/github.com/prometheus/prometheus/model/histogram/float_histogram.go
generated
vendored
Normal file
@@ -0,0 +1,904 @@
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// Licensed 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 histogram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FloatHistogram is similar to Histogram but uses float64 for all
|
||||
// counts. Additionally, bucket counts are absolute and not deltas.
|
||||
//
|
||||
// A FloatHistogram is needed by PromQL to handle operations that might result
|
||||
// in fractional counts. Since the counts in a histogram are unlikely to be too
|
||||
// large to be represented precisely by a float64, a FloatHistogram can also be
|
||||
// used to represent a histogram with integer counts and thus serves as a more
|
||||
// generalized representation.
|
||||
type FloatHistogram struct {
|
||||
// Counter reset information.
|
||||
CounterResetHint CounterResetHint
|
||||
// Currently valid schema numbers are -4 <= n <= 8. They are all for
|
||||
// base-2 bucket schemas, where 1 is a bucket boundary in each case, and
|
||||
// then each power of two is divided into 2^n logarithmic buckets. Or
|
||||
// in other words, each bucket boundary is the previous boundary times
|
||||
// 2^(2^-n).
|
||||
Schema int32
|
||||
// Width of the zero bucket.
|
||||
ZeroThreshold float64
|
||||
// Observations falling into the zero bucket. Must be zero or positive.
|
||||
ZeroCount float64
|
||||
// Total number of observations. Must be zero or positive.
|
||||
Count float64
|
||||
// Sum of observations. This is also used as the stale marker.
|
||||
Sum float64
|
||||
// Spans for positive and negative buckets (see Span below).
|
||||
PositiveSpans, NegativeSpans []Span
|
||||
// Observation counts in buckets. Each represents an absolute count and
|
||||
// must be zero or positive.
|
||||
PositiveBuckets, NegativeBuckets []float64
|
||||
}
|
||||
|
||||
// Copy returns a deep copy of the Histogram.
|
||||
func (h *FloatHistogram) Copy() *FloatHistogram {
|
||||
c := *h
|
||||
|
||||
if h.PositiveSpans != nil {
|
||||
c.PositiveSpans = make([]Span, len(h.PositiveSpans))
|
||||
copy(c.PositiveSpans, h.PositiveSpans)
|
||||
}
|
||||
if h.NegativeSpans != nil {
|
||||
c.NegativeSpans = make([]Span, len(h.NegativeSpans))
|
||||
copy(c.NegativeSpans, h.NegativeSpans)
|
||||
}
|
||||
if h.PositiveBuckets != nil {
|
||||
c.PositiveBuckets = make([]float64, len(h.PositiveBuckets))
|
||||
copy(c.PositiveBuckets, h.PositiveBuckets)
|
||||
}
|
||||
if h.NegativeBuckets != nil {
|
||||
c.NegativeBuckets = make([]float64, len(h.NegativeBuckets))
|
||||
copy(c.NegativeBuckets, h.NegativeBuckets)
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
// CopyToSchema works like Copy, but the returned deep copy has the provided
|
||||
// target schema, which must be ≤ the original schema (i.e. it must have a lower
|
||||
// resolution).
|
||||
func (h *FloatHistogram) CopyToSchema(targetSchema int32) *FloatHistogram {
|
||||
if targetSchema == h.Schema {
|
||||
// Fast path.
|
||||
return h.Copy()
|
||||
}
|
||||
if targetSchema > h.Schema {
|
||||
panic(fmt.Errorf("cannot copy from schema %d to %d", h.Schema, targetSchema))
|
||||
}
|
||||
c := FloatHistogram{
|
||||
Schema: targetSchema,
|
||||
ZeroThreshold: h.ZeroThreshold,
|
||||
ZeroCount: h.ZeroCount,
|
||||
Count: h.Count,
|
||||
Sum: h.Sum,
|
||||
}
|
||||
|
||||
// TODO(beorn7): This is a straight-forward implementation using merging
|
||||
// iterators for the original buckets and then adding one merged bucket
|
||||
// after another to the newly created FloatHistogram. It's well possible
|
||||
// that a more involved implementation performs much better, which we
|
||||
// could do if this code path turns out to be performance-critical.
|
||||
var iInSpan, index int32
|
||||
for iSpan, iBucket, it := -1, -1, h.floatBucketIterator(true, 0, targetSchema); it.Next(); {
|
||||
b := it.At()
|
||||
c.PositiveSpans, c.PositiveBuckets, iSpan, iBucket, iInSpan = addBucket(
|
||||
b, c.PositiveSpans, c.PositiveBuckets, iSpan, iBucket, iInSpan, index,
|
||||
)
|
||||
index = b.Index
|
||||
}
|
||||
for iSpan, iBucket, it := -1, -1, h.floatBucketIterator(false, 0, targetSchema); it.Next(); {
|
||||
b := it.At()
|
||||
c.NegativeSpans, c.NegativeBuckets, iSpan, iBucket, iInSpan = addBucket(
|
||||
b, c.NegativeSpans, c.NegativeBuckets, iSpan, iBucket, iInSpan, index,
|
||||
)
|
||||
index = b.Index
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
// String returns a string representation of the Histogram.
|
||||
func (h *FloatHistogram) String() string {
|
||||
var sb strings.Builder
|
||||
fmt.Fprintf(&sb, "{count:%g, sum:%g", h.Count, h.Sum)
|
||||
|
||||
var nBuckets []Bucket[float64]
|
||||
for it := h.NegativeBucketIterator(); it.Next(); {
|
||||
bucket := it.At()
|
||||
if bucket.Count != 0 {
|
||||
nBuckets = append(nBuckets, it.At())
|
||||
}
|
||||
}
|
||||
for i := len(nBuckets) - 1; i >= 0; i-- {
|
||||
fmt.Fprintf(&sb, ", %s", nBuckets[i].String())
|
||||
}
|
||||
|
||||
if h.ZeroCount != 0 {
|
||||
fmt.Fprintf(&sb, ", %s", h.ZeroBucket().String())
|
||||
}
|
||||
|
||||
for it := h.PositiveBucketIterator(); it.Next(); {
|
||||
bucket := it.At()
|
||||
if bucket.Count != 0 {
|
||||
fmt.Fprintf(&sb, ", %s", bucket.String())
|
||||
}
|
||||
}
|
||||
|
||||
sb.WriteRune('}')
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// ZeroBucket returns the zero bucket.
|
||||
func (h *FloatHistogram) ZeroBucket() Bucket[float64] {
|
||||
return Bucket[float64]{
|
||||
Lower: -h.ZeroThreshold,
|
||||
Upper: h.ZeroThreshold,
|
||||
LowerInclusive: true,
|
||||
UpperInclusive: true,
|
||||
Count: h.ZeroCount,
|
||||
}
|
||||
}
|
||||
|
||||
// Scale scales the FloatHistogram by the provided factor, i.e. it scales all
|
||||
// bucket counts including the zero bucket and the count and the sum of
|
||||
// observations. The bucket layout stays the same. This method changes the
|
||||
// receiving histogram directly (rather than acting on a copy). It returns a
|
||||
// pointer to the receiving histogram for convenience.
|
||||
func (h *FloatHistogram) Scale(factor float64) *FloatHistogram {
|
||||
h.ZeroCount *= factor
|
||||
h.Count *= factor
|
||||
h.Sum *= factor
|
||||
for i := range h.PositiveBuckets {
|
||||
h.PositiveBuckets[i] *= factor
|
||||
}
|
||||
for i := range h.NegativeBuckets {
|
||||
h.NegativeBuckets[i] *= factor
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// Add adds the provided other histogram to the receiving histogram. Count, Sum,
|
||||
// and buckets from the other histogram are added to the corresponding
|
||||
// components of the receiving histogram. Buckets in the other histogram that do
|
||||
// not exist in the receiving histogram are inserted into the latter. The
|
||||
// resulting histogram might have buckets with a population of zero or directly
|
||||
// adjacent spans (offset=0). To normalize those, call the Compact method.
|
||||
//
|
||||
// The method reconciles differences in the zero threshold and in the schema,
|
||||
// but the schema of the other histogram must be ≥ the schema of the receiving
|
||||
// histogram (i.e. must have an equal or higher resolution). This means that the
|
||||
// schema of the receiving histogram won't change. Its zero threshold, however,
|
||||
// will change if needed. The other histogram will not be modified in any case.
|
||||
//
|
||||
// This method returns a pointer to the receiving histogram for convenience.
|
||||
func (h *FloatHistogram) Add(other *FloatHistogram) *FloatHistogram {
|
||||
otherZeroCount := h.reconcileZeroBuckets(other)
|
||||
h.ZeroCount += otherZeroCount
|
||||
h.Count += other.Count
|
||||
h.Sum += other.Sum
|
||||
|
||||
// TODO(beorn7): If needed, this can be optimized by inspecting the
|
||||
// spans in other and create missing buckets in h in batches.
|
||||
var iInSpan, index int32
|
||||
for iSpan, iBucket, it := -1, -1, other.floatBucketIterator(true, h.ZeroThreshold, h.Schema); it.Next(); {
|
||||
b := it.At()
|
||||
h.PositiveSpans, h.PositiveBuckets, iSpan, iBucket, iInSpan = addBucket(
|
||||
b, h.PositiveSpans, h.PositiveBuckets, iSpan, iBucket, iInSpan, index,
|
||||
)
|
||||
index = b.Index
|
||||
}
|
||||
for iSpan, iBucket, it := -1, -1, other.floatBucketIterator(false, h.ZeroThreshold, h.Schema); it.Next(); {
|
||||
b := it.At()
|
||||
h.NegativeSpans, h.NegativeBuckets, iSpan, iBucket, iInSpan = addBucket(
|
||||
b, h.NegativeSpans, h.NegativeBuckets, iSpan, iBucket, iInSpan, index,
|
||||
)
|
||||
index = b.Index
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// Sub works like Add but subtracts the other histogram.
|
||||
func (h *FloatHistogram) Sub(other *FloatHistogram) *FloatHistogram {
|
||||
otherZeroCount := h.reconcileZeroBuckets(other)
|
||||
h.ZeroCount -= otherZeroCount
|
||||
h.Count -= other.Count
|
||||
h.Sum -= other.Sum
|
||||
|
||||
// TODO(beorn7): If needed, this can be optimized by inspecting the
|
||||
// spans in other and create missing buckets in h in batches.
|
||||
var iInSpan, index int32
|
||||
for iSpan, iBucket, it := -1, -1, other.floatBucketIterator(true, h.ZeroThreshold, h.Schema); it.Next(); {
|
||||
b := it.At()
|
||||
b.Count *= -1
|
||||
h.PositiveSpans, h.PositiveBuckets, iSpan, iBucket, iInSpan = addBucket(
|
||||
b, h.PositiveSpans, h.PositiveBuckets, iSpan, iBucket, iInSpan, index,
|
||||
)
|
||||
index = b.Index
|
||||
}
|
||||
for iSpan, iBucket, it := -1, -1, other.floatBucketIterator(false, h.ZeroThreshold, h.Schema); it.Next(); {
|
||||
b := it.At()
|
||||
b.Count *= -1
|
||||
h.NegativeSpans, h.NegativeBuckets, iSpan, iBucket, iInSpan = addBucket(
|
||||
b, h.NegativeSpans, h.NegativeBuckets, iSpan, iBucket, iInSpan, index,
|
||||
)
|
||||
index = b.Index
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// Equals returns true if the given float histogram matches exactly.
|
||||
// Exact match is when there are no new buckets (even empty) and no missing buckets,
|
||||
// and all the bucket values match. Spans can have different empty length spans in between,
|
||||
// but they must represent the same bucket layout to match.
|
||||
func (h *FloatHistogram) Equals(h2 *FloatHistogram) bool {
|
||||
if h2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if h.Schema != h2.Schema || h.ZeroThreshold != h2.ZeroThreshold ||
|
||||
h.ZeroCount != h2.ZeroCount || h.Count != h2.Count || h.Sum != h2.Sum {
|
||||
return false
|
||||
}
|
||||
|
||||
if !spansMatch(h.PositiveSpans, h2.PositiveSpans) {
|
||||
return false
|
||||
}
|
||||
if !spansMatch(h.NegativeSpans, h2.NegativeSpans) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !bucketsMatch(h.PositiveBuckets, h2.PositiveBuckets) {
|
||||
return false
|
||||
}
|
||||
if !bucketsMatch(h.NegativeBuckets, h2.NegativeBuckets) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// addBucket takes the "coordinates" of the last bucket that was handled and
|
||||
// adds the provided bucket after it. If a corresponding bucket exists, the
|
||||
// count is added. If not, the bucket is inserted. The updated slices and the
|
||||
// coordinates of the inserted or added-to bucket are returned.
|
||||
func addBucket(
|
||||
b Bucket[float64],
|
||||
spans []Span, buckets []float64,
|
||||
iSpan, iBucket int,
|
||||
iInSpan, index int32,
|
||||
) (
|
||||
newSpans []Span, newBuckets []float64,
|
||||
newISpan, newIBucket int, newIInSpan int32,
|
||||
) {
|
||||
if iSpan == -1 {
|
||||
// First add, check if it is before all spans.
|
||||
if len(spans) == 0 || spans[0].Offset > b.Index {
|
||||
// Add bucket before all others.
|
||||
buckets = append(buckets, 0)
|
||||
copy(buckets[1:], buckets)
|
||||
buckets[0] = b.Count
|
||||
if len(spans) > 0 && spans[0].Offset == b.Index+1 {
|
||||
spans[0].Length++
|
||||
spans[0].Offset--
|
||||
return spans, buckets, 0, 0, 0
|
||||
}
|
||||
spans = append(spans, Span{})
|
||||
copy(spans[1:], spans)
|
||||
spans[0] = Span{Offset: b.Index, Length: 1}
|
||||
if len(spans) > 1 {
|
||||
// Convert the absolute offset in the formerly
|
||||
// first span to a relative offset.
|
||||
spans[1].Offset -= b.Index + 1
|
||||
}
|
||||
return spans, buckets, 0, 0, 0
|
||||
}
|
||||
if spans[0].Offset == b.Index {
|
||||
// Just add to first bucket.
|
||||
buckets[0] += b.Count
|
||||
return spans, buckets, 0, 0, 0
|
||||
}
|
||||
// We are behind the first bucket, so set everything to the
|
||||
// first bucket and continue normally.
|
||||
iSpan, iBucket, iInSpan = 0, 0, 0
|
||||
index = spans[0].Offset
|
||||
}
|
||||
deltaIndex := b.Index - index
|
||||
for {
|
||||
remainingInSpan := int32(spans[iSpan].Length) - iInSpan
|
||||
if deltaIndex < remainingInSpan {
|
||||
// Bucket is in current span.
|
||||
iBucket += int(deltaIndex)
|
||||
iInSpan += deltaIndex
|
||||
buckets[iBucket] += b.Count
|
||||
return spans, buckets, iSpan, iBucket, iInSpan
|
||||
}
|
||||
deltaIndex -= remainingInSpan
|
||||
iBucket += int(remainingInSpan)
|
||||
iSpan++
|
||||
if iSpan == len(spans) || deltaIndex < spans[iSpan].Offset {
|
||||
// Bucket is in gap behind previous span (or there are no further spans).
|
||||
buckets = append(buckets, 0)
|
||||
copy(buckets[iBucket+1:], buckets[iBucket:])
|
||||
buckets[iBucket] = b.Count
|
||||
if deltaIndex == 0 {
|
||||
// Directly after previous span, extend previous span.
|
||||
if iSpan < len(spans) {
|
||||
spans[iSpan].Offset--
|
||||
}
|
||||
iSpan--
|
||||
iInSpan = int32(spans[iSpan].Length)
|
||||
spans[iSpan].Length++
|
||||
return spans, buckets, iSpan, iBucket, iInSpan
|
||||
}
|
||||
if iSpan < len(spans) && deltaIndex == spans[iSpan].Offset-1 {
|
||||
// Directly before next span, extend next span.
|
||||
iInSpan = 0
|
||||
spans[iSpan].Offset--
|
||||
spans[iSpan].Length++
|
||||
return spans, buckets, iSpan, iBucket, iInSpan
|
||||
}
|
||||
// No next span, or next span is not directly adjacent to new bucket.
|
||||
// Add new span.
|
||||
iInSpan = 0
|
||||
if iSpan < len(spans) {
|
||||
spans[iSpan].Offset -= deltaIndex + 1
|
||||
}
|
||||
spans = append(spans, Span{})
|
||||
copy(spans[iSpan+1:], spans[iSpan:])
|
||||
spans[iSpan] = Span{Length: 1, Offset: deltaIndex}
|
||||
return spans, buckets, iSpan, iBucket, iInSpan
|
||||
}
|
||||
// Try start of next span.
|
||||
deltaIndex -= spans[iSpan].Offset
|
||||
iInSpan = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Compact eliminates empty buckets at the beginning and end of each span, then
|
||||
// merges spans that are consecutive or at most maxEmptyBuckets apart, and
|
||||
// finally splits spans that contain more consecutive empty buckets than
|
||||
// maxEmptyBuckets. (The actual implementation might do something more efficient
|
||||
// but with the same result.) The compaction happens "in place" in the
|
||||
// receiving histogram, but a pointer to it is returned for convenience.
|
||||
//
|
||||
// The ideal value for maxEmptyBuckets depends on circumstances. The motivation
|
||||
// to set maxEmptyBuckets > 0 is the assumption that is is less overhead to
|
||||
// represent very few empty buckets explicitly within one span than cutting the
|
||||
// one span into two to treat the empty buckets as a gap between the two spans,
|
||||
// both in terms of storage requirement as well as in terms of encoding and
|
||||
// decoding effort. However, the tradeoffs are subtle. For one, they are
|
||||
// different in the exposition format vs. in a TSDB chunk vs. for the in-memory
|
||||
// representation as Go types. In the TSDB, as an additional aspects, the span
|
||||
// layout is only stored once per chunk, while many histograms with that same
|
||||
// chunk layout are then only stored with their buckets (so that even a single
|
||||
// empty bucket will be stored many times).
|
||||
//
|
||||
// For the Go types, an additional Span takes 8 bytes. Similarly, an additional
|
||||
// bucket takes 8 bytes. Therefore, with a single separating empty bucket, both
|
||||
// options have the same storage requirement, but the single-span solution is
|
||||
// easier to iterate through. Still, the safest bet is to use maxEmptyBuckets==0
|
||||
// and only use a larger number if you know what you are doing.
|
||||
func (h *FloatHistogram) Compact(maxEmptyBuckets int) *FloatHistogram {
|
||||
h.PositiveBuckets, h.PositiveSpans = compactBuckets(
|
||||
h.PositiveBuckets, h.PositiveSpans, maxEmptyBuckets, false,
|
||||
)
|
||||
h.NegativeBuckets, h.NegativeSpans = compactBuckets(
|
||||
h.NegativeBuckets, h.NegativeSpans, maxEmptyBuckets, false,
|
||||
)
|
||||
return h
|
||||
}
|
||||
|
||||
// DetectReset returns true if the receiving histogram is missing any buckets
|
||||
// that have a non-zero population in the provided previous histogram. It also
|
||||
// returns true if any count (in any bucket, in the zero count, or in the count
|
||||
// of observations, but NOT the sum of observations) is smaller in the receiving
|
||||
// histogram compared to the previous histogram. Otherwise, it returns false.
|
||||
//
|
||||
// Special behavior in case the Schema or the ZeroThreshold are not the same in
|
||||
// both histograms:
|
||||
//
|
||||
// - A decrease of the ZeroThreshold or an increase of the Schema (i.e. an
|
||||
// increase of resolution) can only happen together with a reset. Thus, the
|
||||
// method returns true in either case.
|
||||
//
|
||||
// - Upon an increase of the ZeroThreshold, the buckets in the previous
|
||||
// histogram that fall within the new ZeroThreshold are added to the ZeroCount
|
||||
// of the previous histogram (without mutating the provided previous
|
||||
// histogram). The scenario that a populated bucket of the previous histogram
|
||||
// is partially within, partially outside of the new ZeroThreshold, can only
|
||||
// happen together with a counter reset and therefore shortcuts to returning
|
||||
// true.
|
||||
//
|
||||
// - Upon a decrease of the Schema, the buckets of the previous histogram are
|
||||
// merged so that they match the new, lower-resolution schema (again without
|
||||
// mutating the provided previous histogram).
|
||||
//
|
||||
// Note that this kind of reset detection is quite expensive. Ideally, resets
|
||||
// are detected at ingest time and stored in the TSDB, so that the reset
|
||||
// information can be read directly from there rather than be detected each time
|
||||
// again.
|
||||
func (h *FloatHistogram) DetectReset(previous *FloatHistogram) bool {
|
||||
if h.Count < previous.Count {
|
||||
return true
|
||||
}
|
||||
if h.Schema > previous.Schema {
|
||||
return true
|
||||
}
|
||||
if h.ZeroThreshold < previous.ZeroThreshold {
|
||||
// ZeroThreshold decreased.
|
||||
return true
|
||||
}
|
||||
previousZeroCount, newThreshold := previous.zeroCountForLargerThreshold(h.ZeroThreshold)
|
||||
if newThreshold != h.ZeroThreshold {
|
||||
// ZeroThreshold is within a populated bucket in previous
|
||||
// histogram.
|
||||
return true
|
||||
}
|
||||
if h.ZeroCount < previousZeroCount {
|
||||
return true
|
||||
}
|
||||
currIt := h.floatBucketIterator(true, h.ZeroThreshold, h.Schema)
|
||||
prevIt := previous.floatBucketIterator(true, h.ZeroThreshold, h.Schema)
|
||||
if detectReset(currIt, prevIt) {
|
||||
return true
|
||||
}
|
||||
currIt = h.floatBucketIterator(false, h.ZeroThreshold, h.Schema)
|
||||
prevIt = previous.floatBucketIterator(false, h.ZeroThreshold, h.Schema)
|
||||
return detectReset(currIt, prevIt)
|
||||
}
|
||||
|
||||
func detectReset(currIt, prevIt BucketIterator[float64]) bool {
|
||||
if !prevIt.Next() {
|
||||
return false // If no buckets in previous histogram, nothing can be reset.
|
||||
}
|
||||
prevBucket := prevIt.At()
|
||||
if !currIt.Next() {
|
||||
// No bucket in current, but at least one in previous
|
||||
// histogram. Check if any of those are non-zero, in which case
|
||||
// this is a reset.
|
||||
for {
|
||||
if prevBucket.Count != 0 {
|
||||
return true
|
||||
}
|
||||
if !prevIt.Next() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
currBucket := currIt.At()
|
||||
for {
|
||||
// Forward currIt until we find the bucket corresponding to prevBucket.
|
||||
for currBucket.Index < prevBucket.Index {
|
||||
if !currIt.Next() {
|
||||
// Reached end of currIt early, therefore
|
||||
// previous histogram has a bucket that the
|
||||
// current one does not have. Unlass all
|
||||
// remaining buckets in the previous histogram
|
||||
// are unpopulated, this is a reset.
|
||||
for {
|
||||
if prevBucket.Count != 0 {
|
||||
return true
|
||||
}
|
||||
if !prevIt.Next() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
currBucket = currIt.At()
|
||||
}
|
||||
if currBucket.Index > prevBucket.Index {
|
||||
// Previous histogram has a bucket the current one does
|
||||
// not have. If it's populated, it's a reset.
|
||||
if prevBucket.Count != 0 {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
// We have reached corresponding buckets in both iterators.
|
||||
// We can finally compare the counts.
|
||||
if currBucket.Count < prevBucket.Count {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if !prevIt.Next() {
|
||||
// Reached end of prevIt without finding offending buckets.
|
||||
return false
|
||||
}
|
||||
prevBucket = prevIt.At()
|
||||
}
|
||||
}
|
||||
|
||||
// PositiveBucketIterator returns a BucketIterator to iterate over all positive
|
||||
// buckets in ascending order (starting next to the zero bucket and going up).
|
||||
func (h *FloatHistogram) PositiveBucketIterator() BucketIterator[float64] {
|
||||
return h.floatBucketIterator(true, 0, h.Schema)
|
||||
}
|
||||
|
||||
// NegativeBucketIterator returns a BucketIterator to iterate over all negative
|
||||
// buckets in descending order (starting next to the zero bucket and going
|
||||
// down).
|
||||
func (h *FloatHistogram) NegativeBucketIterator() BucketIterator[float64] {
|
||||
return h.floatBucketIterator(false, 0, h.Schema)
|
||||
}
|
||||
|
||||
// PositiveReverseBucketIterator returns a BucketIterator to iterate over all
|
||||
// positive buckets in descending order (starting at the highest bucket and
|
||||
// going down towards the zero bucket).
|
||||
func (h *FloatHistogram) PositiveReverseBucketIterator() BucketIterator[float64] {
|
||||
return newReverseFloatBucketIterator(h.PositiveSpans, h.PositiveBuckets, h.Schema, true)
|
||||
}
|
||||
|
||||
// NegativeReverseBucketIterator returns a BucketIterator to iterate over all
|
||||
// negative buckets in ascending order (starting at the lowest bucket and going
|
||||
// up towards the zero bucket).
|
||||
func (h *FloatHistogram) NegativeReverseBucketIterator() BucketIterator[float64] {
|
||||
return newReverseFloatBucketIterator(h.NegativeSpans, h.NegativeBuckets, h.Schema, false)
|
||||
}
|
||||
|
||||
// AllBucketIterator returns a BucketIterator to iterate over all negative,
|
||||
// zero, and positive buckets in ascending order (starting at the lowest bucket
|
||||
// and going up). If the highest negative bucket or the lowest positive bucket
|
||||
// overlap with the zero bucket, their upper or lower boundary, respectively, is
|
||||
// set to the zero threshold.
|
||||
func (h *FloatHistogram) AllBucketIterator() BucketIterator[float64] {
|
||||
return &allFloatBucketIterator{
|
||||
h: h,
|
||||
negIter: h.NegativeReverseBucketIterator(),
|
||||
posIter: h.PositiveBucketIterator(),
|
||||
state: -1,
|
||||
}
|
||||
}
|
||||
|
||||
// zeroCountForLargerThreshold returns what the histogram's zero count would be
|
||||
// if the ZeroThreshold had the provided larger (or equal) value. If the
|
||||
// provided value is less than the histogram's ZeroThreshold, the method panics.
|
||||
// If the largerThreshold ends up within a populated bucket of the histogram, it
|
||||
// is adjusted upwards to the lower limit of that bucket (all in terms of
|
||||
// absolute values) and that bucket's count is included in the returned
|
||||
// count. The adjusted threshold is returned, too.
|
||||
func (h *FloatHistogram) zeroCountForLargerThreshold(largerThreshold float64) (count, threshold float64) {
|
||||
// Fast path.
|
||||
if largerThreshold == h.ZeroThreshold {
|
||||
return h.ZeroCount, largerThreshold
|
||||
}
|
||||
if largerThreshold < h.ZeroThreshold {
|
||||
panic(fmt.Errorf("new threshold %f is less than old threshold %f", largerThreshold, h.ZeroThreshold))
|
||||
}
|
||||
outer:
|
||||
for {
|
||||
count = h.ZeroCount
|
||||
i := h.PositiveBucketIterator()
|
||||
for i.Next() {
|
||||
b := i.At()
|
||||
if b.Lower >= largerThreshold {
|
||||
break
|
||||
}
|
||||
count += b.Count // Bucket to be merged into zero bucket.
|
||||
if b.Upper > largerThreshold {
|
||||
// New threshold ended up within a bucket. if it's
|
||||
// populated, we need to adjust largerThreshold before
|
||||
// we are done here.
|
||||
if b.Count != 0 {
|
||||
largerThreshold = b.Upper
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
i = h.NegativeBucketIterator()
|
||||
for i.Next() {
|
||||
b := i.At()
|
||||
if b.Upper <= -largerThreshold {
|
||||
break
|
||||
}
|
||||
count += b.Count // Bucket to be merged into zero bucket.
|
||||
if b.Lower < -largerThreshold {
|
||||
// New threshold ended up within a bucket. If
|
||||
// it's populated, we need to adjust
|
||||
// largerThreshold and have to redo the whole
|
||||
// thing because the treatment of the positive
|
||||
// buckets is invalid now.
|
||||
if b.Count != 0 {
|
||||
largerThreshold = -b.Lower
|
||||
continue outer
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return count, largerThreshold
|
||||
}
|
||||
}
|
||||
|
||||
// trimBucketsInZeroBucket removes all buckets that are within the zero
|
||||
// bucket. It assumes that the zero threshold is at a bucket boundary and that
|
||||
// the counts in the buckets to remove are already part of the zero count.
|
||||
func (h *FloatHistogram) trimBucketsInZeroBucket() {
|
||||
i := h.PositiveBucketIterator()
|
||||
bucketsIdx := 0
|
||||
for i.Next() {
|
||||
b := i.At()
|
||||
if b.Lower >= h.ZeroThreshold {
|
||||
break
|
||||
}
|
||||
h.PositiveBuckets[bucketsIdx] = 0
|
||||
bucketsIdx++
|
||||
}
|
||||
i = h.NegativeBucketIterator()
|
||||
bucketsIdx = 0
|
||||
for i.Next() {
|
||||
b := i.At()
|
||||
if b.Upper <= -h.ZeroThreshold {
|
||||
break
|
||||
}
|
||||
h.NegativeBuckets[bucketsIdx] = 0
|
||||
bucketsIdx++
|
||||
}
|
||||
// We are abusing Compact to trim the buckets set to zero
|
||||
// above. Premature compacting could cause additional cost, but this
|
||||
// code path is probably rarely used anyway.
|
||||
h.Compact(0)
|
||||
}
|
||||
|
||||
// reconcileZeroBuckets finds a zero bucket large enough to include the zero
|
||||
// buckets of both histograms (the receiving histogram and the other histogram)
|
||||
// with a zero threshold that is not within a populated bucket in either
|
||||
// histogram. This method modifies the receiving histogram accourdingly, but
|
||||
// leaves the other histogram as is. Instead, it returns the zero count the
|
||||
// other histogram would have if it were modified.
|
||||
func (h *FloatHistogram) reconcileZeroBuckets(other *FloatHistogram) float64 {
|
||||
otherZeroCount := other.ZeroCount
|
||||
otherZeroThreshold := other.ZeroThreshold
|
||||
|
||||
for otherZeroThreshold != h.ZeroThreshold {
|
||||
if h.ZeroThreshold > otherZeroThreshold {
|
||||
otherZeroCount, otherZeroThreshold = other.zeroCountForLargerThreshold(h.ZeroThreshold)
|
||||
}
|
||||
if otherZeroThreshold > h.ZeroThreshold {
|
||||
h.ZeroCount, h.ZeroThreshold = h.zeroCountForLargerThreshold(otherZeroThreshold)
|
||||
h.trimBucketsInZeroBucket()
|
||||
}
|
||||
}
|
||||
return otherZeroCount
|
||||
}
|
||||
|
||||
// floatBucketIterator is a low-level constructor for bucket iterators.
|
||||
//
|
||||
// If positive is true, the returned iterator iterates through the positive
|
||||
// buckets, otherwise through the negative buckets.
|
||||
//
|
||||
// If absoluteStartValue is < the lowest absolute value of any upper bucket
|
||||
// boundary, the iterator starts with the first bucket. Otherwise, it will skip
|
||||
// all buckets with an absolute value of their upper boundary ≤
|
||||
// absoluteStartValue.
|
||||
//
|
||||
// targetSchema must be ≤ the schema of FloatHistogram (and of course within the
|
||||
// legal values for schemas in general). The buckets are merged to match the
|
||||
// targetSchema prior to iterating (without mutating FloatHistogram).
|
||||
func (h *FloatHistogram) floatBucketIterator(
|
||||
positive bool, absoluteStartValue float64, targetSchema int32,
|
||||
) *floatBucketIterator {
|
||||
if targetSchema > h.Schema {
|
||||
panic(fmt.Errorf("cannot merge from schema %d to %d", h.Schema, targetSchema))
|
||||
}
|
||||
i := &floatBucketIterator{
|
||||
baseBucketIterator: baseBucketIterator[float64, float64]{
|
||||
schema: h.Schema,
|
||||
positive: positive,
|
||||
},
|
||||
targetSchema: targetSchema,
|
||||
absoluteStartValue: absoluteStartValue,
|
||||
}
|
||||
if positive {
|
||||
i.spans = h.PositiveSpans
|
||||
i.buckets = h.PositiveBuckets
|
||||
} else {
|
||||
i.spans = h.NegativeSpans
|
||||
i.buckets = h.NegativeBuckets
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// reverseFloatbucketiterator is a low-level constructor for reverse bucket iterators.
|
||||
func newReverseFloatBucketIterator(
|
||||
spans []Span, buckets []float64, schema int32, positive bool,
|
||||
) *reverseFloatBucketIterator {
|
||||
r := &reverseFloatBucketIterator{
|
||||
baseBucketIterator: baseBucketIterator[float64, float64]{
|
||||
schema: schema,
|
||||
spans: spans,
|
||||
buckets: buckets,
|
||||
positive: positive,
|
||||
},
|
||||
}
|
||||
|
||||
r.spansIdx = len(r.spans) - 1
|
||||
r.bucketsIdx = len(r.buckets) - 1
|
||||
if r.spansIdx >= 0 {
|
||||
r.idxInSpan = int32(r.spans[r.spansIdx].Length) - 1
|
||||
}
|
||||
r.currIdx = 0
|
||||
for _, s := range r.spans {
|
||||
r.currIdx += s.Offset + int32(s.Length)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
type floatBucketIterator struct {
|
||||
baseBucketIterator[float64, float64]
|
||||
|
||||
targetSchema int32 // targetSchema is the schema to merge to and must be ≤ schema.
|
||||
origIdx int32 // The bucket index within the original schema.
|
||||
absoluteStartValue float64 // Never return buckets with an upper bound ≤ this value.
|
||||
}
|
||||
|
||||
func (i *floatBucketIterator) Next() bool {
|
||||
if i.spansIdx >= len(i.spans) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Copy all of these into local variables so that we can forward to the
|
||||
// next bucket and then roll back if needed.
|
||||
origIdx, spansIdx, idxInSpan := i.origIdx, i.spansIdx, i.idxInSpan
|
||||
span := i.spans[spansIdx]
|
||||
firstPass := true
|
||||
i.currCount = 0
|
||||
|
||||
mergeLoop: // Merge together all buckets from the original schema that fall into one bucket in the targetSchema.
|
||||
for {
|
||||
if i.bucketsIdx == 0 {
|
||||
// Seed origIdx for the first bucket.
|
||||
origIdx = span.Offset
|
||||
} else {
|
||||
origIdx++
|
||||
}
|
||||
for idxInSpan >= span.Length {
|
||||
// We have exhausted the current span and have to find a new
|
||||
// one. We even handle pathologic spans of length 0 here.
|
||||
idxInSpan = 0
|
||||
spansIdx++
|
||||
if spansIdx >= len(i.spans) {
|
||||
if firstPass {
|
||||
return false
|
||||
}
|
||||
break mergeLoop
|
||||
}
|
||||
span = i.spans[spansIdx]
|
||||
origIdx += span.Offset
|
||||
}
|
||||
currIdx := i.targetIdx(origIdx)
|
||||
if firstPass {
|
||||
i.currIdx = currIdx
|
||||
firstPass = false
|
||||
} else if currIdx != i.currIdx {
|
||||
// Reached next bucket in targetSchema.
|
||||
// Do not actually forward to the next bucket, but break out.
|
||||
break mergeLoop
|
||||
}
|
||||
i.currCount += i.buckets[i.bucketsIdx]
|
||||
idxInSpan++
|
||||
i.bucketsIdx++
|
||||
i.origIdx, i.spansIdx, i.idxInSpan = origIdx, spansIdx, idxInSpan
|
||||
if i.schema == i.targetSchema {
|
||||
// Don't need to test the next bucket for mergeability
|
||||
// if we have no schema change anyway.
|
||||
break mergeLoop
|
||||
}
|
||||
}
|
||||
// Skip buckets before absoluteStartValue.
|
||||
// TODO(beorn7): Maybe do something more efficient than this recursive call.
|
||||
if getBound(i.currIdx, i.targetSchema) <= i.absoluteStartValue {
|
||||
return i.Next()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// targetIdx returns the bucket index within i.targetSchema for the given bucket
|
||||
// index within i.schema.
|
||||
func (i *floatBucketIterator) targetIdx(idx int32) int32 {
|
||||
if i.schema == i.targetSchema {
|
||||
// Fast path for the common case. The below would yield the same
|
||||
// result, just with more effort.
|
||||
return idx
|
||||
}
|
||||
return ((idx - 1) >> (i.schema - i.targetSchema)) + 1
|
||||
}
|
||||
|
||||
type reverseFloatBucketIterator struct {
|
||||
baseBucketIterator[float64, float64]
|
||||
idxInSpan int32 // Changed from uint32 to allow negative values for exhaustion detection.
|
||||
}
|
||||
|
||||
func (i *reverseFloatBucketIterator) Next() bool {
|
||||
i.currIdx--
|
||||
if i.bucketsIdx < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for i.idxInSpan < 0 {
|
||||
// We have exhausted the current span and have to find a new
|
||||
// one. We'll even handle pathologic spans of length 0.
|
||||
i.spansIdx--
|
||||
i.idxInSpan = int32(i.spans[i.spansIdx].Length) - 1
|
||||
i.currIdx -= i.spans[i.spansIdx+1].Offset
|
||||
}
|
||||
|
||||
i.currCount = i.buckets[i.bucketsIdx]
|
||||
i.bucketsIdx--
|
||||
i.idxInSpan--
|
||||
return true
|
||||
}
|
||||
|
||||
type allFloatBucketIterator struct {
|
||||
h *FloatHistogram
|
||||
negIter, posIter BucketIterator[float64]
|
||||
// -1 means we are iterating negative buckets.
|
||||
// 0 means it is time for the zero bucket.
|
||||
// 1 means we are iterating positive buckets.
|
||||
// Anything else means iteration is over.
|
||||
state int8
|
||||
currBucket Bucket[float64]
|
||||
}
|
||||
|
||||
func (i *allFloatBucketIterator) Next() bool {
|
||||
switch i.state {
|
||||
case -1:
|
||||
if i.negIter.Next() {
|
||||
i.currBucket = i.negIter.At()
|
||||
if i.currBucket.Upper > -i.h.ZeroThreshold {
|
||||
i.currBucket.Upper = -i.h.ZeroThreshold
|
||||
}
|
||||
return true
|
||||
}
|
||||
i.state = 0
|
||||
return i.Next()
|
||||
case 0:
|
||||
i.state = 1
|
||||
if i.h.ZeroCount > 0 {
|
||||
i.currBucket = Bucket[float64]{
|
||||
Lower: -i.h.ZeroThreshold,
|
||||
Upper: i.h.ZeroThreshold,
|
||||
LowerInclusive: true,
|
||||
UpperInclusive: true,
|
||||
Count: i.h.ZeroCount,
|
||||
// Index is irrelevant for the zero bucket.
|
||||
}
|
||||
return true
|
||||
}
|
||||
return i.Next()
|
||||
case 1:
|
||||
if i.posIter.Next() {
|
||||
i.currBucket = i.posIter.At()
|
||||
if i.currBucket.Lower < i.h.ZeroThreshold {
|
||||
i.currBucket.Lower = i.h.ZeroThreshold
|
||||
}
|
||||
return true
|
||||
}
|
||||
i.state = 42
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *allFloatBucketIterator) At() Bucket[float64] {
|
||||
return i.currBucket
|
||||
}
|
||||
548
vendor/github.com/prometheus/prometheus/model/histogram/generic.go
generated
vendored
Normal file
548
vendor/github.com/prometheus/prometheus/model/histogram/generic.go
generated
vendored
Normal file
@@ -0,0 +1,548 @@
|
||||
// Copyright 2022 The Prometheus Authors
|
||||
// Licensed 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 histogram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BucketCount is a type constraint for the count in a bucket, which can be
|
||||
// float64 (for type FloatHistogram) or uint64 (for type Histogram).
|
||||
type BucketCount interface {
|
||||
float64 | uint64
|
||||
}
|
||||
|
||||
// InternalBucketCount is used internally by Histogram and FloatHistogram. The
|
||||
// difference to the BucketCount above is that Histogram internally uses deltas
|
||||
// between buckets rather than absolute counts (while FloatHistogram uses
|
||||
// absolute counts directly). Go type parameters don't allow type
|
||||
// specialization. Therefore, where special treatment of deltas between buckets
|
||||
// vs. absolute counts is important, this information has to be provided as a
|
||||
// separate boolean parameter "deltaBuckets"
|
||||
type InternalBucketCount interface {
|
||||
float64 | int64
|
||||
}
|
||||
|
||||
// Bucket represents a bucket with lower and upper limit and the absolute count
|
||||
// of samples in the bucket. It also specifies if each limit is inclusive or
|
||||
// not. (Mathematically, inclusive limits create a closed interval, and
|
||||
// non-inclusive limits an open interval.)
|
||||
//
|
||||
// To represent cumulative buckets, Lower is set to -Inf, and the Count is then
|
||||
// cumulative (including the counts of all buckets for smaller values).
|
||||
type Bucket[BC BucketCount] struct {
|
||||
Lower, Upper float64
|
||||
LowerInclusive, UpperInclusive bool
|
||||
Count BC
|
||||
|
||||
// Index within schema. To easily compare buckets that share the same
|
||||
// schema and sign (positive or negative). Irrelevant for the zero bucket.
|
||||
Index int32
|
||||
}
|
||||
|
||||
// String returns a string representation of a Bucket, using the usual
|
||||
// mathematical notation of '['/']' for inclusive bounds and '('/')' for
|
||||
// non-inclusive bounds.
|
||||
func (b Bucket[BC]) String() string {
|
||||
var sb strings.Builder
|
||||
if b.LowerInclusive {
|
||||
sb.WriteRune('[')
|
||||
} else {
|
||||
sb.WriteRune('(')
|
||||
}
|
||||
fmt.Fprintf(&sb, "%g,%g", b.Lower, b.Upper)
|
||||
if b.UpperInclusive {
|
||||
sb.WriteRune(']')
|
||||
} else {
|
||||
sb.WriteRune(')')
|
||||
}
|
||||
fmt.Fprintf(&sb, ":%v", b.Count)
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// BucketIterator iterates over the buckets of a Histogram, returning decoded
|
||||
// buckets.
|
||||
type BucketIterator[BC BucketCount] interface {
|
||||
// Next advances the iterator by one.
|
||||
Next() bool
|
||||
// At returns the current bucket.
|
||||
At() Bucket[BC]
|
||||
}
|
||||
|
||||
// baseBucketIterator provides a struct that is shared by most BucketIterator
|
||||
// implementations, together with an implementation of the At method. This
|
||||
// iterator can be embedded in full implementations of BucketIterator to save on
|
||||
// code replication.
|
||||
type baseBucketIterator[BC BucketCount, IBC InternalBucketCount] struct {
|
||||
schema int32
|
||||
spans []Span
|
||||
buckets []IBC
|
||||
|
||||
positive bool // Whether this is for positive buckets.
|
||||
|
||||
spansIdx int // Current span within spans slice.
|
||||
idxInSpan uint32 // Index in the current span. 0 <= idxInSpan < span.Length.
|
||||
bucketsIdx int // Current bucket within buckets slice.
|
||||
|
||||
currCount IBC // Count in the current bucket.
|
||||
currIdx int32 // The actual bucket index.
|
||||
}
|
||||
|
||||
func (b baseBucketIterator[BC, IBC]) At() Bucket[BC] {
|
||||
bucket := Bucket[BC]{
|
||||
Count: BC(b.currCount),
|
||||
Index: b.currIdx,
|
||||
}
|
||||
if b.positive {
|
||||
bucket.Upper = getBound(b.currIdx, b.schema)
|
||||
bucket.Lower = getBound(b.currIdx-1, b.schema)
|
||||
} else {
|
||||
bucket.Lower = -getBound(b.currIdx, b.schema)
|
||||
bucket.Upper = -getBound(b.currIdx-1, b.schema)
|
||||
}
|
||||
bucket.LowerInclusive = bucket.Lower < 0
|
||||
bucket.UpperInclusive = bucket.Upper > 0
|
||||
return bucket
|
||||
}
|
||||
|
||||
// compactBuckets is a generic function used by both Histogram.Compact and
|
||||
// FloatHistogram.Compact. Set deltaBuckets to true if the provided buckets are
|
||||
// deltas. Set it to false if the buckets contain absolute counts.
|
||||
func compactBuckets[IBC InternalBucketCount](buckets []IBC, spans []Span, maxEmptyBuckets int, deltaBuckets bool) ([]IBC, []Span) {
|
||||
// Fast path: If there are no empty buckets AND no offset in any span is
|
||||
// <= maxEmptyBuckets AND no span has length 0, there is nothing to do and we can return
|
||||
// immediately. We check that first because it's cheap and presumably
|
||||
// common.
|
||||
nothingToDo := true
|
||||
var currentBucketAbsolute IBC
|
||||
for _, bucket := range buckets {
|
||||
if deltaBuckets {
|
||||
currentBucketAbsolute += bucket
|
||||
} else {
|
||||
currentBucketAbsolute = bucket
|
||||
}
|
||||
if currentBucketAbsolute == 0 {
|
||||
nothingToDo = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if nothingToDo {
|
||||
for _, span := range spans {
|
||||
if int(span.Offset) <= maxEmptyBuckets || span.Length == 0 {
|
||||
nothingToDo = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if nothingToDo {
|
||||
return buckets, spans
|
||||
}
|
||||
}
|
||||
|
||||
var iBucket, iSpan int
|
||||
var posInSpan uint32
|
||||
currentBucketAbsolute = 0
|
||||
|
||||
// Helper function.
|
||||
emptyBucketsHere := func() int {
|
||||
i := 0
|
||||
abs := currentBucketAbsolute
|
||||
for uint32(i)+posInSpan < spans[iSpan].Length && abs == 0 {
|
||||
i++
|
||||
if i+iBucket >= len(buckets) {
|
||||
break
|
||||
}
|
||||
abs = buckets[i+iBucket]
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// Merge spans with zero-offset to avoid special cases later.
|
||||
if len(spans) > 1 {
|
||||
for i, span := range spans[1:] {
|
||||
if span.Offset == 0 {
|
||||
spans[iSpan].Length += span.Length
|
||||
continue
|
||||
}
|
||||
iSpan++
|
||||
if i+1 != iSpan {
|
||||
spans[iSpan] = span
|
||||
}
|
||||
}
|
||||
spans = spans[:iSpan+1]
|
||||
iSpan = 0
|
||||
}
|
||||
|
||||
// Merge spans with zero-length to avoid special cases later.
|
||||
for i, span := range spans {
|
||||
if span.Length == 0 {
|
||||
if i+1 < len(spans) {
|
||||
spans[i+1].Offset += span.Offset
|
||||
}
|
||||
continue
|
||||
}
|
||||
if i != iSpan {
|
||||
spans[iSpan] = span
|
||||
}
|
||||
iSpan++
|
||||
}
|
||||
spans = spans[:iSpan]
|
||||
iSpan = 0
|
||||
|
||||
// Cut out empty buckets from start and end of spans, no matter
|
||||
// what. Also cut out empty buckets from the middle of a span but only
|
||||
// if there are more than maxEmptyBuckets consecutive empty buckets.
|
||||
for iBucket < len(buckets) {
|
||||
if deltaBuckets {
|
||||
currentBucketAbsolute += buckets[iBucket]
|
||||
} else {
|
||||
currentBucketAbsolute = buckets[iBucket]
|
||||
}
|
||||
if nEmpty := emptyBucketsHere(); nEmpty > 0 {
|
||||
if posInSpan > 0 &&
|
||||
nEmpty < int(spans[iSpan].Length-posInSpan) &&
|
||||
nEmpty <= maxEmptyBuckets {
|
||||
// The empty buckets are in the middle of a
|
||||
// span, and there are few enough to not bother.
|
||||
// Just fast-forward.
|
||||
iBucket += nEmpty
|
||||
if deltaBuckets {
|
||||
currentBucketAbsolute = 0
|
||||
}
|
||||
posInSpan += uint32(nEmpty)
|
||||
continue
|
||||
}
|
||||
// In all other cases, we cut out the empty buckets.
|
||||
if deltaBuckets && iBucket+nEmpty < len(buckets) {
|
||||
currentBucketAbsolute = -buckets[iBucket]
|
||||
buckets[iBucket+nEmpty] += buckets[iBucket]
|
||||
}
|
||||
buckets = append(buckets[:iBucket], buckets[iBucket+nEmpty:]...)
|
||||
if posInSpan == 0 {
|
||||
// Start of span.
|
||||
if nEmpty == int(spans[iSpan].Length) {
|
||||
// The whole span is empty.
|
||||
offset := spans[iSpan].Offset
|
||||
spans = append(spans[:iSpan], spans[iSpan+1:]...)
|
||||
if len(spans) > iSpan {
|
||||
spans[iSpan].Offset += offset + int32(nEmpty)
|
||||
}
|
||||
continue
|
||||
}
|
||||
spans[iSpan].Length -= uint32(nEmpty)
|
||||
spans[iSpan].Offset += int32(nEmpty)
|
||||
continue
|
||||
}
|
||||
// It's in the middle or in the end of the span.
|
||||
// Split the current span.
|
||||
newSpan := Span{
|
||||
Offset: int32(nEmpty),
|
||||
Length: spans[iSpan].Length - posInSpan - uint32(nEmpty),
|
||||
}
|
||||
spans[iSpan].Length = posInSpan
|
||||
// In any case, we have to split to the next span.
|
||||
iSpan++
|
||||
posInSpan = 0
|
||||
if newSpan.Length == 0 {
|
||||
// The span is empty, so we were already at the end of a span.
|
||||
// We don't have to insert the new span, just adjust the next
|
||||
// span's offset, if there is one.
|
||||
if iSpan < len(spans) {
|
||||
spans[iSpan].Offset += int32(nEmpty)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Insert the new span.
|
||||
spans = append(spans, Span{})
|
||||
if iSpan+1 < len(spans) {
|
||||
copy(spans[iSpan+1:], spans[iSpan:])
|
||||
}
|
||||
spans[iSpan] = newSpan
|
||||
continue
|
||||
}
|
||||
iBucket++
|
||||
posInSpan++
|
||||
if posInSpan >= spans[iSpan].Length {
|
||||
posInSpan = 0
|
||||
iSpan++
|
||||
}
|
||||
}
|
||||
if maxEmptyBuckets == 0 || len(buckets) == 0 {
|
||||
return buckets, spans
|
||||
}
|
||||
|
||||
// Finally, check if any offsets between spans are small enough to merge
|
||||
// the spans.
|
||||
iBucket = int(spans[0].Length)
|
||||
if deltaBuckets {
|
||||
currentBucketAbsolute = 0
|
||||
for _, bucket := range buckets[:iBucket] {
|
||||
currentBucketAbsolute += bucket
|
||||
}
|
||||
}
|
||||
iSpan = 1
|
||||
for iSpan < len(spans) {
|
||||
if int(spans[iSpan].Offset) > maxEmptyBuckets {
|
||||
l := int(spans[iSpan].Length)
|
||||
if deltaBuckets {
|
||||
for _, bucket := range buckets[iBucket : iBucket+l] {
|
||||
currentBucketAbsolute += bucket
|
||||
}
|
||||
}
|
||||
iBucket += l
|
||||
iSpan++
|
||||
continue
|
||||
}
|
||||
// Merge span with previous one and insert empty buckets.
|
||||
offset := int(spans[iSpan].Offset)
|
||||
spans[iSpan-1].Length += uint32(offset) + spans[iSpan].Length
|
||||
spans = append(spans[:iSpan], spans[iSpan+1:]...)
|
||||
newBuckets := make([]IBC, len(buckets)+offset)
|
||||
copy(newBuckets, buckets[:iBucket])
|
||||
copy(newBuckets[iBucket+offset:], buckets[iBucket:])
|
||||
if deltaBuckets {
|
||||
newBuckets[iBucket] = -currentBucketAbsolute
|
||||
newBuckets[iBucket+offset] += currentBucketAbsolute
|
||||
}
|
||||
iBucket += offset
|
||||
buckets = newBuckets
|
||||
currentBucketAbsolute = buckets[iBucket]
|
||||
// Note that with many merges, it would be more efficient to
|
||||
// first record all the chunks of empty buckets to insert and
|
||||
// then do it in one go through all the buckets.
|
||||
}
|
||||
|
||||
return buckets, spans
|
||||
}
|
||||
|
||||
func bucketsMatch[IBC InternalBucketCount](b1, b2 []IBC) bool {
|
||||
if len(b1) != len(b2) {
|
||||
return false
|
||||
}
|
||||
for i, b := range b1 {
|
||||
if b != b2[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func getBound(idx, schema int32) float64 {
|
||||
// Here a bit of context about the behavior for the last bucket counting
|
||||
// regular numbers (called simply "last bucket" below) and the bucket
|
||||
// counting observations of ±Inf (called "inf bucket" below, with an idx
|
||||
// one higher than that of the "last bucket"):
|
||||
//
|
||||
// If we apply the usual formula to the last bucket, its upper bound
|
||||
// would be calculated as +Inf. The reason is that the max possible
|
||||
// regular float64 number (math.MaxFloat64) doesn't coincide with one of
|
||||
// the calculated bucket boundaries. So the calculated boundary has to
|
||||
// be larger than math.MaxFloat64, and the only float64 larger than
|
||||
// math.MaxFloat64 is +Inf. However, we want to count actual
|
||||
// observations of ±Inf in the inf bucket. Therefore, we have to treat
|
||||
// the upper bound of the last bucket specially and set it to
|
||||
// math.MaxFloat64. (The upper bound of the inf bucket, with its idx
|
||||
// being one higher than that of the last bucket, naturally comes out as
|
||||
// +Inf by the usual formula. So that's fine.)
|
||||
//
|
||||
// math.MaxFloat64 has a frac of 0.9999999999999999 and an exp of
|
||||
// 1024. If there were a float64 number following math.MaxFloat64, it
|
||||
// would have a frac of 1.0 and an exp of 1024, or equivalently a frac
|
||||
// of 0.5 and an exp of 1025. However, since frac must be smaller than
|
||||
// 1, and exp must be smaller than 1025, either representation overflows
|
||||
// a float64. (Which, in turn, is the reason that math.MaxFloat64 is the
|
||||
// largest possible float64. Q.E.D.) However, the formula for
|
||||
// calculating the upper bound from the idx and schema of the last
|
||||
// bucket results in precisely that. It is either frac=1.0 & exp=1024
|
||||
// (for schema < 0) or frac=0.5 & exp=1025 (for schema >=0). (This is,
|
||||
// by the way, a power of two where the exponent itself is a power of
|
||||
// two, 2¹⁰ in fact, which coinicides with a bucket boundary in all
|
||||
// schemas.) So these are the special cases we have to catch below.
|
||||
if schema < 0 {
|
||||
exp := int(idx) << -schema
|
||||
if exp == 1024 {
|
||||
// This is the last bucket before the overflow bucket
|
||||
// (for ±Inf observations). Return math.MaxFloat64 as
|
||||
// explained above.
|
||||
return math.MaxFloat64
|
||||
}
|
||||
return math.Ldexp(1, exp)
|
||||
}
|
||||
|
||||
fracIdx := idx & ((1 << schema) - 1)
|
||||
frac := exponentialBounds[schema][fracIdx]
|
||||
exp := (int(idx) >> schema) + 1
|
||||
if frac == 0.5 && exp == 1025 {
|
||||
// This is the last bucket before the overflow bucket (for ±Inf
|
||||
// observations). Return math.MaxFloat64 as explained above.
|
||||
return math.MaxFloat64
|
||||
}
|
||||
return math.Ldexp(frac, exp)
|
||||
}
|
||||
|
||||
// exponentialBounds is a precalculated table of bucket bounds in the interval
|
||||
// [0.5,1) in schema 0 to 8.
|
||||
var exponentialBounds = [][]float64{
|
||||
// Schema "0":
|
||||
{0.5},
|
||||
// Schema 1:
|
||||
{0.5, 0.7071067811865475},
|
||||
// Schema 2:
|
||||
{0.5, 0.5946035575013605, 0.7071067811865475, 0.8408964152537144},
|
||||
// Schema 3:
|
||||
{
|
||||
0.5, 0.5452538663326288, 0.5946035575013605, 0.6484197773255048,
|
||||
0.7071067811865475, 0.7711054127039704, 0.8408964152537144, 0.9170040432046711,
|
||||
},
|
||||
// Schema 4:
|
||||
{
|
||||
0.5, 0.5221368912137069, 0.5452538663326288, 0.5693943173783458,
|
||||
0.5946035575013605, 0.620928906036742, 0.6484197773255048, 0.6771277734684463,
|
||||
0.7071067811865475, 0.7384130729697496, 0.7711054127039704, 0.805245165974627,
|
||||
0.8408964152537144, 0.8781260801866495, 0.9170040432046711, 0.9576032806985735,
|
||||
},
|
||||
// Schema 5:
|
||||
{
|
||||
0.5, 0.5109485743270583, 0.5221368912137069, 0.5335702003384117,
|
||||
0.5452538663326288, 0.5571933712979462, 0.5693943173783458, 0.5818624293887887,
|
||||
0.5946035575013605, 0.6076236799902344, 0.620928906036742, 0.6345254785958666,
|
||||
0.6484197773255048, 0.6626183215798706, 0.6771277734684463, 0.6919549409819159,
|
||||
0.7071067811865475, 0.7225904034885232, 0.7384130729697496, 0.7545822137967112,
|
||||
0.7711054127039704, 0.7879904225539431, 0.805245165974627, 0.8228777390769823,
|
||||
0.8408964152537144, 0.8593096490612387, 0.8781260801866495, 0.8973545375015533,
|
||||
0.9170040432046711, 0.9370838170551498, 0.9576032806985735, 0.9785720620876999,
|
||||
},
|
||||
// Schema 6:
|
||||
{
|
||||
0.5, 0.5054446430258502, 0.5109485743270583, 0.5165124395106142,
|
||||
0.5221368912137069, 0.5278225891802786, 0.5335702003384117, 0.5393803988785598,
|
||||
0.5452538663326288, 0.5511912916539204, 0.5571933712979462, 0.5632608093041209,
|
||||
0.5693943173783458, 0.5755946149764913, 0.5818624293887887, 0.5881984958251406,
|
||||
0.5946035575013605, 0.6010783657263515, 0.6076236799902344, 0.6142402680534349,
|
||||
0.620928906036742, 0.6276903785123455, 0.6345254785958666, 0.6414350080393891,
|
||||
0.6484197773255048, 0.6554806057623822, 0.6626183215798706, 0.6698337620266515,
|
||||
0.6771277734684463, 0.6845012114872953, 0.6919549409819159, 0.6994898362691555,
|
||||
0.7071067811865475, 0.7148066691959849, 0.7225904034885232, 0.7304588970903234,
|
||||
0.7384130729697496, 0.7464538641456323, 0.7545822137967112, 0.762799075372269,
|
||||
0.7711054127039704, 0.7795022001189185, 0.7879904225539431, 0.7965710756711334,
|
||||
0.805245165974627, 0.8140137109286738, 0.8228777390769823, 0.8318382901633681,
|
||||
0.8408964152537144, 0.8500531768592616, 0.8593096490612387, 0.8686669176368529,
|
||||
0.8781260801866495, 0.8876882462632604, 0.8973545375015533, 0.9071260877501991,
|
||||
0.9170040432046711, 0.9269895625416926, 0.9370838170551498, 0.9472879907934827,
|
||||
0.9576032806985735, 0.9680308967461471, 0.9785720620876999, 0.9892280131939752,
|
||||
},
|
||||
// Schema 7:
|
||||
{
|
||||
0.5, 0.5027149505564014, 0.5054446430258502, 0.5081891574554764,
|
||||
0.5109485743270583, 0.5137229745593818, 0.5165124395106142, 0.5193170509806894,
|
||||
0.5221368912137069, 0.5249720429003435, 0.5278225891802786, 0.5306886136446309,
|
||||
0.5335702003384117, 0.5364674337629877, 0.5393803988785598, 0.5423091811066545,
|
||||
0.5452538663326288, 0.5482145409081883, 0.5511912916539204, 0.5541842058618393,
|
||||
0.5571933712979462, 0.5602188762048033, 0.5632608093041209, 0.5663192597993595,
|
||||
0.5693943173783458, 0.572486072215902, 0.5755946149764913, 0.5787200368168754,
|
||||
0.5818624293887887, 0.585021884841625, 0.5881984958251406, 0.5913923554921704,
|
||||
0.5946035575013605, 0.5978321960199137, 0.6010783657263515, 0.6043421618132907,
|
||||
0.6076236799902344, 0.6109230164863786, 0.6142402680534349, 0.6175755319684665,
|
||||
0.620928906036742, 0.6243004885946023, 0.6276903785123455, 0.6310986751971253,
|
||||
0.6345254785958666, 0.637970889198196, 0.6414350080393891, 0.6449179367033329,
|
||||
0.6484197773255048, 0.6519406325959679, 0.6554806057623822, 0.659039800633032,
|
||||
0.6626183215798706, 0.6662162735415805, 0.6698337620266515, 0.6734708931164728,
|
||||
0.6771277734684463, 0.6808045103191123, 0.6845012114872953, 0.688217985377265,
|
||||
0.6919549409819159, 0.6957121878859629, 0.6994898362691555, 0.7032879969095076,
|
||||
0.7071067811865475, 0.7109463010845827, 0.7148066691959849, 0.718687998724491,
|
||||
0.7225904034885232, 0.7265139979245261, 0.7304588970903234, 0.7344252166684908,
|
||||
0.7384130729697496, 0.7424225829363761, 0.7464538641456323, 0.7505070348132126,
|
||||
0.7545822137967112, 0.7586795205991071, 0.762799075372269, 0.7669409989204777,
|
||||
0.7711054127039704, 0.7752924388424999, 0.7795022001189185, 0.7837348199827764,
|
||||
0.7879904225539431, 0.7922691326262467, 0.7965710756711334, 0.8008963778413465,
|
||||
0.805245165974627, 0.8096175675974316, 0.8140137109286738, 0.8184337248834821,
|
||||
0.8228777390769823, 0.8273458838280969, 0.8318382901633681, 0.8363550898207981,
|
||||
0.8408964152537144, 0.8454623996346523, 0.8500531768592616, 0.8546688815502312,
|
||||
0.8593096490612387, 0.8639756154809185, 0.8686669176368529, 0.8733836930995842,
|
||||
0.8781260801866495, 0.8828942179666361, 0.8876882462632604, 0.8925083056594671,
|
||||
0.8973545375015533, 0.9022270839033115, 0.9071260877501991, 0.9120516927035263,
|
||||
0.9170040432046711, 0.9219832844793128, 0.9269895625416926, 0.9320230241988943,
|
||||
0.9370838170551498, 0.9421720895161669, 0.9472879907934827, 0.9524316709088368,
|
||||
0.9576032806985735, 0.9628029718180622, 0.9680308967461471, 0.9732872087896164,
|
||||
0.9785720620876999, 0.9838856116165875, 0.9892280131939752, 0.9945994234836328,
|
||||
},
|
||||
// Schema 8:
|
||||
{
|
||||
0.5, 0.5013556375251013, 0.5027149505564014, 0.5040779490592088,
|
||||
0.5054446430258502, 0.5068150424757447, 0.5081891574554764, 0.509566998038869,
|
||||
0.5109485743270583, 0.5123338964485679, 0.5137229745593818, 0.5151158188430205,
|
||||
0.5165124395106142, 0.5179128468009786, 0.5193170509806894, 0.520725062344158,
|
||||
0.5221368912137069, 0.5235525479396449, 0.5249720429003435, 0.526395386502313,
|
||||
0.5278225891802786, 0.5292536613972564, 0.5306886136446309, 0.5321274564422321,
|
||||
0.5335702003384117, 0.5350168559101208, 0.5364674337629877, 0.5379219445313954,
|
||||
0.5393803988785598, 0.5408428074966075, 0.5423091811066545, 0.5437795304588847,
|
||||
0.5452538663326288, 0.5467321995364429, 0.5482145409081883, 0.549700901315111,
|
||||
0.5511912916539204, 0.5526857228508706, 0.5541842058618393, 0.5556867516724088,
|
||||
0.5571933712979462, 0.5587040757836845, 0.5602188762048033, 0.5617377836665098,
|
||||
0.5632608093041209, 0.564787964283144, 0.5663192597993595, 0.5678547070789026,
|
||||
0.5693943173783458, 0.5709381019847808, 0.572486072215902, 0.5740382394200894,
|
||||
0.5755946149764913, 0.5771552102951081, 0.5787200368168754, 0.5802891060137493,
|
||||
0.5818624293887887, 0.5834400184762408, 0.585021884841625, 0.5866080400818185,
|
||||
0.5881984958251406, 0.5897932637314379, 0.5913923554921704, 0.5929957828304968,
|
||||
0.5946035575013605, 0.5962156912915756, 0.5978321960199137, 0.5994530835371903,
|
||||
0.6010783657263515, 0.6027080545025619, 0.6043421618132907, 0.6059806996384005,
|
||||
0.6076236799902344, 0.6092711149137041, 0.6109230164863786, 0.6125793968185725,
|
||||
0.6142402680534349, 0.6159056423670379, 0.6175755319684665, 0.6192499490999082,
|
||||
0.620928906036742, 0.622612415087629, 0.6243004885946023, 0.6259931389331581,
|
||||
0.6276903785123455, 0.6293922197748583, 0.6310986751971253, 0.6328097572894031,
|
||||
0.6345254785958666, 0.6362458516947014, 0.637970889198196, 0.6397006037528346,
|
||||
0.6414350080393891, 0.6431741147730128, 0.6449179367033329, 0.6466664866145447,
|
||||
0.6484197773255048, 0.6501778216898253, 0.6519406325959679, 0.6537082229673385,
|
||||
0.6554806057623822, 0.6572577939746774, 0.659039800633032, 0.6608266388015788,
|
||||
0.6626183215798706, 0.6644148621029772, 0.6662162735415805, 0.6680225691020727,
|
||||
0.6698337620266515, 0.6716498655934177, 0.6734708931164728, 0.6752968579460171,
|
||||
0.6771277734684463, 0.6789636531064505, 0.6808045103191123, 0.6826503586020058,
|
||||
0.6845012114872953, 0.6863570825438342, 0.688217985377265, 0.690083933630119,
|
||||
0.6919549409819159, 0.6938310211492645, 0.6957121878859629, 0.6975984549830999,
|
||||
0.6994898362691555, 0.7013863456101023, 0.7032879969095076, 0.7051948041086352,
|
||||
0.7071067811865475, 0.7090239421602076, 0.7109463010845827, 0.7128738720527471,
|
||||
0.7148066691959849, 0.7167447066838943, 0.718687998724491, 0.7206365595643126,
|
||||
0.7225904034885232, 0.7245495448210174, 0.7265139979245261, 0.7284837772007218,
|
||||
0.7304588970903234, 0.7324393720732029, 0.7344252166684908, 0.7364164454346837,
|
||||
0.7384130729697496, 0.7404151139112358, 0.7424225829363761, 0.7444354947621984,
|
||||
0.7464538641456323, 0.7484777058836176, 0.7505070348132126, 0.7525418658117031,
|
||||
0.7545822137967112, 0.7566280937263048, 0.7586795205991071, 0.7607365094544071,
|
||||
0.762799075372269, 0.7648672334736434, 0.7669409989204777, 0.7690203869158282,
|
||||
0.7711054127039704, 0.7731960915705107, 0.7752924388424999, 0.7773944698885442,
|
||||
0.7795022001189185, 0.7816156449856788, 0.7837348199827764, 0.7858597406461707,
|
||||
0.7879904225539431, 0.7901268813264122, 0.7922691326262467, 0.7944171921585818,
|
||||
0.7965710756711334, 0.7987307989543135, 0.8008963778413465, 0.8030678282083853,
|
||||
0.805245165974627, 0.8074284071024302, 0.8096175675974316, 0.8118126635086642,
|
||||
0.8140137109286738, 0.8162207259936375, 0.8184337248834821, 0.820652723822003,
|
||||
0.8228777390769823, 0.8251087869603088, 0.8273458838280969, 0.8295890460808079,
|
||||
0.8318382901633681, 0.8340936325652911, 0.8363550898207981, 0.8386226785089391,
|
||||
0.8408964152537144, 0.8431763167241966, 0.8454623996346523, 0.8477546807446661,
|
||||
0.8500531768592616, 0.8523579048290255, 0.8546688815502312, 0.8569861239649629,
|
||||
0.8593096490612387, 0.8616394738731368, 0.8639756154809185, 0.8663180910111553,
|
||||
0.8686669176368529, 0.871022112577578, 0.8733836930995842, 0.8757516765159389,
|
||||
0.8781260801866495, 0.8805069215187917, 0.8828942179666361, 0.8852879870317771,
|
||||
0.8876882462632604, 0.890095013257712, 0.8925083056594671, 0.8949281411607002,
|
||||
0.8973545375015533, 0.8997875124702672, 0.9022270839033115, 0.9046732696855155,
|
||||
0.9071260877501991, 0.909585556079304, 0.9120516927035263, 0.9145245157024483,
|
||||
0.9170040432046711, 0.9194902933879467, 0.9219832844793128, 0.9244830347552253,
|
||||
0.9269895625416926, 0.92950288621441, 0.9320230241988943, 0.9345499949706191,
|
||||
0.9370838170551498, 0.93962450902828, 0.9421720895161669, 0.9447265771954693,
|
||||
0.9472879907934827, 0.9498563490882775, 0.9524316709088368, 0.9550139751351947,
|
||||
0.9576032806985735, 0.9601996065815236, 0.9628029718180622, 0.9654133954938133,
|
||||
0.9680308967461471, 0.9706554947643201, 0.9732872087896164, 0.9759260581154889,
|
||||
0.9785720620876999, 0.9812252401044634, 0.9838856116165875, 0.9865531961276168,
|
||||
0.9892280131939752, 0.9919100824251095, 0.9945994234836328, 0.9972960560854698,
|
||||
},
|
||||
}
|
||||
450
vendor/github.com/prometheus/prometheus/model/histogram/histogram.go
generated
vendored
Normal file
450
vendor/github.com/prometheus/prometheus/model/histogram/histogram.go
generated
vendored
Normal file
@@ -0,0 +1,450 @@
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// Licensed 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 histogram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CounterResetHint contains the known information about a counter reset,
|
||||
// or alternatively that we are dealing with a gauge histogram, where counter resets do not apply.
|
||||
type CounterResetHint byte
|
||||
|
||||
const (
|
||||
UnknownCounterReset CounterResetHint = iota // UnknownCounterReset means we cannot say if this histogram signals a counter reset or not.
|
||||
CounterReset // CounterReset means there was definitely a counter reset starting from this histogram.
|
||||
NotCounterReset // NotCounterReset means there was definitely no counter reset with this histogram.
|
||||
GaugeType // GaugeType means this is a gauge histogram, where counter resets do not happen.
|
||||
)
|
||||
|
||||
// Histogram encodes a sparse, high-resolution histogram. See the design
|
||||
// document for full details:
|
||||
// https://docs.google.com/document/d/1cLNv3aufPZb3fNfaJgdaRBZsInZKKIHo9E6HinJVbpM/edit#
|
||||
//
|
||||
// The most tricky bit is how bucket indices represent real bucket boundaries.
|
||||
// An example for schema 0 (by which each bucket is twice as wide as the
|
||||
// previous bucket):
|
||||
//
|
||||
// Bucket boundaries → [-2,-1) [-1,-0.5) [-0.5,-0.25) ... [-0.001,0.001] ... (0.25,0.5] (0.5,1] (1,2] ....
|
||||
// ↑ ↑ ↑ ↑ ↑ ↑ ↑
|
||||
// Zero bucket (width e.g. 0.001) → | | | ZB | | |
|
||||
// Positive bucket indices → | | | ... -1 0 1 2 3
|
||||
// Negative bucket indices → 3 2 1 0 -1 ...
|
||||
//
|
||||
// Which bucket indices are actually used is determined by the spans.
|
||||
type Histogram struct {
|
||||
// Counter reset information.
|
||||
CounterResetHint CounterResetHint
|
||||
// Currently valid schema numbers are -4 <= n <= 8. They are all for
|
||||
// base-2 bucket schemas, where 1 is a bucket boundary in each case, and
|
||||
// then each power of two is divided into 2^n logarithmic buckets. Or
|
||||
// in other words, each bucket boundary is the previous boundary times
|
||||
// 2^(2^-n).
|
||||
Schema int32
|
||||
// Width of the zero bucket.
|
||||
ZeroThreshold float64
|
||||
// Observations falling into the zero bucket.
|
||||
ZeroCount uint64
|
||||
// Total number of observations.
|
||||
Count uint64
|
||||
// Sum of observations. This is also used as the stale marker.
|
||||
Sum float64
|
||||
// Spans for positive and negative buckets (see Span below).
|
||||
PositiveSpans, NegativeSpans []Span
|
||||
// Observation counts in buckets. The first element is an absolute
|
||||
// count. All following ones are deltas relative to the previous
|
||||
// element.
|
||||
PositiveBuckets, NegativeBuckets []int64
|
||||
}
|
||||
|
||||
// A Span defines a continuous sequence of buckets.
|
||||
type Span struct {
|
||||
// Gap to previous span (always positive), or starting index for the 1st
|
||||
// span (which can be negative).
|
||||
Offset int32
|
||||
// Length of the span.
|
||||
Length uint32
|
||||
}
|
||||
|
||||
// Copy returns a deep copy of the Histogram.
|
||||
func (h *Histogram) Copy() *Histogram {
|
||||
c := *h
|
||||
|
||||
if len(h.PositiveSpans) != 0 {
|
||||
c.PositiveSpans = make([]Span, len(h.PositiveSpans))
|
||||
copy(c.PositiveSpans, h.PositiveSpans)
|
||||
}
|
||||
if len(h.NegativeSpans) != 0 {
|
||||
c.NegativeSpans = make([]Span, len(h.NegativeSpans))
|
||||
copy(c.NegativeSpans, h.NegativeSpans)
|
||||
}
|
||||
if len(h.PositiveBuckets) != 0 {
|
||||
c.PositiveBuckets = make([]int64, len(h.PositiveBuckets))
|
||||
copy(c.PositiveBuckets, h.PositiveBuckets)
|
||||
}
|
||||
if len(h.NegativeBuckets) != 0 {
|
||||
c.NegativeBuckets = make([]int64, len(h.NegativeBuckets))
|
||||
copy(c.NegativeBuckets, h.NegativeBuckets)
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
// String returns a string representation of the Histogram.
|
||||
func (h *Histogram) String() string {
|
||||
var sb strings.Builder
|
||||
fmt.Fprintf(&sb, "{count:%d, sum:%g", h.Count, h.Sum)
|
||||
|
||||
var nBuckets []Bucket[uint64]
|
||||
for it := h.NegativeBucketIterator(); it.Next(); {
|
||||
bucket := it.At()
|
||||
if bucket.Count != 0 {
|
||||
nBuckets = append(nBuckets, it.At())
|
||||
}
|
||||
}
|
||||
for i := len(nBuckets) - 1; i >= 0; i-- {
|
||||
fmt.Fprintf(&sb, ", %s", nBuckets[i].String())
|
||||
}
|
||||
|
||||
if h.ZeroCount != 0 {
|
||||
fmt.Fprintf(&sb, ", %s", h.ZeroBucket().String())
|
||||
}
|
||||
|
||||
for it := h.PositiveBucketIterator(); it.Next(); {
|
||||
bucket := it.At()
|
||||
if bucket.Count != 0 {
|
||||
fmt.Fprintf(&sb, ", %s", bucket.String())
|
||||
}
|
||||
}
|
||||
|
||||
sb.WriteRune('}')
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// ZeroBucket returns the zero bucket.
|
||||
func (h *Histogram) ZeroBucket() Bucket[uint64] {
|
||||
return Bucket[uint64]{
|
||||
Lower: -h.ZeroThreshold,
|
||||
Upper: h.ZeroThreshold,
|
||||
LowerInclusive: true,
|
||||
UpperInclusive: true,
|
||||
Count: h.ZeroCount,
|
||||
}
|
||||
}
|
||||
|
||||
// PositiveBucketIterator returns a BucketIterator to iterate over all positive
|
||||
// buckets in ascending order (starting next to the zero bucket and going up).
|
||||
func (h *Histogram) PositiveBucketIterator() BucketIterator[uint64] {
|
||||
return newRegularBucketIterator(h.PositiveSpans, h.PositiveBuckets, h.Schema, true)
|
||||
}
|
||||
|
||||
// NegativeBucketIterator returns a BucketIterator to iterate over all negative
|
||||
// buckets in descending order (starting next to the zero bucket and going down).
|
||||
func (h *Histogram) NegativeBucketIterator() BucketIterator[uint64] {
|
||||
return newRegularBucketIterator(h.NegativeSpans, h.NegativeBuckets, h.Schema, false)
|
||||
}
|
||||
|
||||
// CumulativeBucketIterator returns a BucketIterator to iterate over a
|
||||
// cumulative view of the buckets. This method currently only supports
|
||||
// Histograms without negative buckets and panics if the Histogram has negative
|
||||
// buckets. It is currently only used for testing.
|
||||
func (h *Histogram) CumulativeBucketIterator() BucketIterator[uint64] {
|
||||
if len(h.NegativeBuckets) > 0 {
|
||||
panic("CumulativeBucketIterator called on Histogram with negative buckets")
|
||||
}
|
||||
return &cumulativeBucketIterator{h: h, posSpansIdx: -1}
|
||||
}
|
||||
|
||||
// Equals returns true if the given histogram matches exactly.
|
||||
// Exact match is when there are no new buckets (even empty) and no missing buckets,
|
||||
// and all the bucket values match. Spans can have different empty length spans in between,
|
||||
// but they must represent the same bucket layout to match.
|
||||
func (h *Histogram) Equals(h2 *Histogram) bool {
|
||||
if h2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if h.Schema != h2.Schema || h.ZeroThreshold != h2.ZeroThreshold ||
|
||||
h.ZeroCount != h2.ZeroCount || h.Count != h2.Count || h.Sum != h2.Sum {
|
||||
return false
|
||||
}
|
||||
|
||||
if !spansMatch(h.PositiveSpans, h2.PositiveSpans) {
|
||||
return false
|
||||
}
|
||||
if !spansMatch(h.NegativeSpans, h2.NegativeSpans) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !bucketsMatch(h.PositiveBuckets, h2.PositiveBuckets) {
|
||||
return false
|
||||
}
|
||||
if !bucketsMatch(h.NegativeBuckets, h2.NegativeBuckets) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// spansMatch returns true if both spans represent the same bucket layout
|
||||
// after combining zero length spans with the next non-zero length span.
|
||||
func spansMatch(s1, s2 []Span) bool {
|
||||
if len(s1) == 0 && len(s2) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
s1idx, s2idx := 0, 0
|
||||
for {
|
||||
if s1idx >= len(s1) {
|
||||
return allEmptySpans(s2[s2idx:])
|
||||
}
|
||||
if s2idx >= len(s2) {
|
||||
return allEmptySpans(s1[s1idx:])
|
||||
}
|
||||
|
||||
currS1, currS2 := s1[s1idx], s2[s2idx]
|
||||
s1idx++
|
||||
s2idx++
|
||||
if currS1.Length == 0 {
|
||||
// This span is zero length, so we add consecutive such spans
|
||||
// until we find a non-zero span.
|
||||
for ; s1idx < len(s1) && s1[s1idx].Length == 0; s1idx++ {
|
||||
currS1.Offset += s1[s1idx].Offset
|
||||
}
|
||||
if s1idx < len(s1) {
|
||||
currS1.Offset += s1[s1idx].Offset
|
||||
currS1.Length = s1[s1idx].Length
|
||||
s1idx++
|
||||
}
|
||||
}
|
||||
if currS2.Length == 0 {
|
||||
// This span is zero length, so we add consecutive such spans
|
||||
// until we find a non-zero span.
|
||||
for ; s2idx < len(s2) && s2[s2idx].Length == 0; s2idx++ {
|
||||
currS2.Offset += s2[s2idx].Offset
|
||||
}
|
||||
if s2idx < len(s2) {
|
||||
currS2.Offset += s2[s2idx].Offset
|
||||
currS2.Length = s2[s2idx].Length
|
||||
s2idx++
|
||||
}
|
||||
}
|
||||
|
||||
if currS1.Length == 0 && currS2.Length == 0 {
|
||||
// The last spans of both set are zero length. Previous spans match.
|
||||
return true
|
||||
}
|
||||
|
||||
if currS1.Offset != currS2.Offset || currS1.Length != currS2.Length {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func allEmptySpans(s []Span) bool {
|
||||
for _, ss := range s {
|
||||
if ss.Length > 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Compact works like FloatHistogram.Compact. See there for detailed
|
||||
// explanations.
|
||||
func (h *Histogram) Compact(maxEmptyBuckets int) *Histogram {
|
||||
h.PositiveBuckets, h.PositiveSpans = compactBuckets(
|
||||
h.PositiveBuckets, h.PositiveSpans, maxEmptyBuckets, true,
|
||||
)
|
||||
h.NegativeBuckets, h.NegativeSpans = compactBuckets(
|
||||
h.NegativeBuckets, h.NegativeSpans, maxEmptyBuckets, true,
|
||||
)
|
||||
return h
|
||||
}
|
||||
|
||||
// ToFloat returns a FloatHistogram representation of the Histogram. It is a
|
||||
// deep copy (e.g. spans are not shared).
|
||||
func (h *Histogram) ToFloat() *FloatHistogram {
|
||||
var (
|
||||
positiveSpans, negativeSpans []Span
|
||||
positiveBuckets, negativeBuckets []float64
|
||||
)
|
||||
if len(h.PositiveSpans) != 0 {
|
||||
positiveSpans = make([]Span, len(h.PositiveSpans))
|
||||
copy(positiveSpans, h.PositiveSpans)
|
||||
}
|
||||
if len(h.NegativeSpans) != 0 {
|
||||
negativeSpans = make([]Span, len(h.NegativeSpans))
|
||||
copy(negativeSpans, h.NegativeSpans)
|
||||
}
|
||||
if len(h.PositiveBuckets) != 0 {
|
||||
positiveBuckets = make([]float64, len(h.PositiveBuckets))
|
||||
var current float64
|
||||
for i, b := range h.PositiveBuckets {
|
||||
current += float64(b)
|
||||
positiveBuckets[i] = current
|
||||
}
|
||||
}
|
||||
if len(h.NegativeBuckets) != 0 {
|
||||
negativeBuckets = make([]float64, len(h.NegativeBuckets))
|
||||
var current float64
|
||||
for i, b := range h.NegativeBuckets {
|
||||
current += float64(b)
|
||||
negativeBuckets[i] = current
|
||||
}
|
||||
}
|
||||
|
||||
return &FloatHistogram{
|
||||
CounterResetHint: h.CounterResetHint,
|
||||
Schema: h.Schema,
|
||||
ZeroThreshold: h.ZeroThreshold,
|
||||
ZeroCount: float64(h.ZeroCount),
|
||||
Count: float64(h.Count),
|
||||
Sum: h.Sum,
|
||||
PositiveSpans: positiveSpans,
|
||||
NegativeSpans: negativeSpans,
|
||||
PositiveBuckets: positiveBuckets,
|
||||
NegativeBuckets: negativeBuckets,
|
||||
}
|
||||
}
|
||||
|
||||
type regularBucketIterator struct {
|
||||
baseBucketIterator[uint64, int64]
|
||||
}
|
||||
|
||||
func newRegularBucketIterator(spans []Span, buckets []int64, schema int32, positive bool) *regularBucketIterator {
|
||||
i := baseBucketIterator[uint64, int64]{
|
||||
schema: schema,
|
||||
spans: spans,
|
||||
buckets: buckets,
|
||||
positive: positive,
|
||||
}
|
||||
return ®ularBucketIterator{i}
|
||||
}
|
||||
|
||||
func (r *regularBucketIterator) Next() bool {
|
||||
if r.spansIdx >= len(r.spans) {
|
||||
return false
|
||||
}
|
||||
span := r.spans[r.spansIdx]
|
||||
// Seed currIdx for the first bucket.
|
||||
if r.bucketsIdx == 0 {
|
||||
r.currIdx = span.Offset
|
||||
} else {
|
||||
r.currIdx++
|
||||
}
|
||||
for r.idxInSpan >= span.Length {
|
||||
// We have exhausted the current span and have to find a new
|
||||
// one. We'll even handle pathologic spans of length 0.
|
||||
r.idxInSpan = 0
|
||||
r.spansIdx++
|
||||
if r.spansIdx >= len(r.spans) {
|
||||
return false
|
||||
}
|
||||
span = r.spans[r.spansIdx]
|
||||
r.currIdx += span.Offset
|
||||
}
|
||||
|
||||
r.currCount += r.buckets[r.bucketsIdx]
|
||||
r.idxInSpan++
|
||||
r.bucketsIdx++
|
||||
return true
|
||||
}
|
||||
|
||||
type cumulativeBucketIterator struct {
|
||||
h *Histogram
|
||||
|
||||
posSpansIdx int // Index in h.PositiveSpans we are in. -1 means 0 bucket.
|
||||
posBucketsIdx int // Index in h.PositiveBuckets.
|
||||
idxInSpan uint32 // Index in the current span. 0 <= idxInSpan < span.Length.
|
||||
|
||||
initialized bool
|
||||
currIdx int32 // The actual bucket index after decoding from spans.
|
||||
currUpper float64 // The upper boundary of the current bucket.
|
||||
currCount int64 // Current non-cumulative count for the current bucket. Does not apply for empty bucket.
|
||||
currCumulativeCount uint64 // Current "cumulative" count for the current bucket.
|
||||
|
||||
// Between 2 spans there could be some empty buckets which
|
||||
// still needs to be counted for cumulative buckets.
|
||||
// When we hit the end of a span, we use this to iterate
|
||||
// through the empty buckets.
|
||||
emptyBucketCount int32
|
||||
}
|
||||
|
||||
func (c *cumulativeBucketIterator) Next() bool {
|
||||
if c.posSpansIdx == -1 {
|
||||
// Zero bucket.
|
||||
c.posSpansIdx++
|
||||
if c.h.ZeroCount == 0 {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
c.currUpper = c.h.ZeroThreshold
|
||||
c.currCount = int64(c.h.ZeroCount)
|
||||
c.currCumulativeCount = uint64(c.currCount)
|
||||
return true
|
||||
}
|
||||
|
||||
if c.posSpansIdx >= len(c.h.PositiveSpans) {
|
||||
return false
|
||||
}
|
||||
|
||||
if c.emptyBucketCount > 0 {
|
||||
// We are traversing through empty buckets at the moment.
|
||||
c.currUpper = getBound(c.currIdx, c.h.Schema)
|
||||
c.currIdx++
|
||||
c.emptyBucketCount--
|
||||
return true
|
||||
}
|
||||
|
||||
span := c.h.PositiveSpans[c.posSpansIdx]
|
||||
if c.posSpansIdx == 0 && !c.initialized {
|
||||
// Initializing.
|
||||
c.currIdx = span.Offset
|
||||
// The first bucket is an absolute value and not a delta with Zero bucket.
|
||||
c.currCount = 0
|
||||
c.initialized = true
|
||||
}
|
||||
|
||||
c.currCount += c.h.PositiveBuckets[c.posBucketsIdx]
|
||||
c.currCumulativeCount += uint64(c.currCount)
|
||||
c.currUpper = getBound(c.currIdx, c.h.Schema)
|
||||
|
||||
c.posBucketsIdx++
|
||||
c.idxInSpan++
|
||||
c.currIdx++
|
||||
if c.idxInSpan >= span.Length {
|
||||
// Move to the next span. This one is done.
|
||||
c.posSpansIdx++
|
||||
c.idxInSpan = 0
|
||||
if c.posSpansIdx < len(c.h.PositiveSpans) {
|
||||
c.emptyBucketCount = c.h.PositiveSpans[c.posSpansIdx].Offset
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *cumulativeBucketIterator) At() Bucket[uint64] {
|
||||
return Bucket[uint64]{
|
||||
Upper: c.currUpper,
|
||||
Lower: math.Inf(-1),
|
||||
UpperInclusive: true,
|
||||
LowerInclusive: true,
|
||||
Count: c.currCumulativeCount,
|
||||
Index: c.currIdx - 1,
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,8 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/cespare/xxhash"
|
||||
"github.com/cespare/xxhash/v2"
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
// Well-known label names used by Prometheus components.
|
||||
@@ -29,10 +30,11 @@ const (
|
||||
BucketLabel = "le"
|
||||
InstanceName = "instance"
|
||||
|
||||
sep = '\xff'
|
||||
labelSep = '\xfe'
|
||||
)
|
||||
|
||||
var seps = []byte{'\xff'}
|
||||
|
||||
// Label is a key/value pair of strings.
|
||||
type Label struct {
|
||||
Name, Value string
|
||||
@@ -70,10 +72,10 @@ func (ls Labels) Bytes(buf []byte) []byte {
|
||||
b.WriteByte(labelSep)
|
||||
for i, l := range ls {
|
||||
if i > 0 {
|
||||
b.WriteByte(sep)
|
||||
b.WriteByte(seps[0])
|
||||
}
|
||||
b.WriteString(l.Name)
|
||||
b.WriteByte(sep)
|
||||
b.WriteByte(seps[0])
|
||||
b.WriteString(l.Value)
|
||||
}
|
||||
return b.Bytes()
|
||||
@@ -118,7 +120,7 @@ func (ls *Labels) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
func (ls Labels) MatchLabels(on bool, names ...string) Labels {
|
||||
matchedLabels := Labels{}
|
||||
|
||||
nameSet := map[string]struct{}{}
|
||||
nameSet := make(map[string]struct{}, len(names))
|
||||
for _, n := range names {
|
||||
nameSet[n] = struct{}{}
|
||||
}
|
||||
@@ -133,14 +135,28 @@ func (ls Labels) MatchLabels(on bool, names ...string) Labels {
|
||||
}
|
||||
|
||||
// Hash returns a hash value for the label set.
|
||||
// Note: the result is not guaranteed to be consistent across different runs of Prometheus.
|
||||
func (ls Labels) Hash() uint64 {
|
||||
// Use xxhash.Sum64(b) for fast path as it's faster.
|
||||
b := make([]byte, 0, 1024)
|
||||
for i, v := range ls {
|
||||
if len(b)+len(v.Name)+len(v.Value)+2 >= cap(b) {
|
||||
// If labels entry is 1KB+ do not allocate whole entry.
|
||||
h := xxhash.New()
|
||||
_, _ = h.Write(b)
|
||||
for _, v := range ls[i:] {
|
||||
_, _ = h.WriteString(v.Name)
|
||||
_, _ = h.Write(seps)
|
||||
_, _ = h.WriteString(v.Value)
|
||||
_, _ = h.Write(seps)
|
||||
}
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
for _, v := range ls {
|
||||
b = append(b, v.Name...)
|
||||
b = append(b, sep)
|
||||
b = append(b, seps[0])
|
||||
b = append(b, v.Value...)
|
||||
b = append(b, sep)
|
||||
b = append(b, seps[0])
|
||||
}
|
||||
return xxhash.Sum64(b)
|
||||
}
|
||||
@@ -157,9 +173,9 @@ func (ls Labels) HashForLabels(b []byte, names ...string) (uint64, []byte) {
|
||||
i++
|
||||
} else {
|
||||
b = append(b, ls[i].Name...)
|
||||
b = append(b, sep)
|
||||
b = append(b, seps[0])
|
||||
b = append(b, ls[i].Value...)
|
||||
b = append(b, sep)
|
||||
b = append(b, seps[0])
|
||||
i++
|
||||
j++
|
||||
}
|
||||
@@ -181,18 +197,18 @@ func (ls Labels) HashWithoutLabels(b []byte, names ...string) (uint64, []byte) {
|
||||
continue
|
||||
}
|
||||
b = append(b, ls[i].Name...)
|
||||
b = append(b, sep)
|
||||
b = append(b, seps[0])
|
||||
b = append(b, ls[i].Value...)
|
||||
b = append(b, sep)
|
||||
b = append(b, seps[0])
|
||||
}
|
||||
return xxhash.Sum64(b), b
|
||||
}
|
||||
|
||||
// WithLabels returns a new labels.Labels from ls that only contains labels matching names.
|
||||
// BytesWithLabels is just as Bytes(), but only for labels matching names.
|
||||
// 'names' have to be sorted in ascending order.
|
||||
func (ls Labels) WithLabels(names ...string) Labels {
|
||||
ret := make([]Label, 0, len(ls))
|
||||
|
||||
func (ls Labels) BytesWithLabels(buf []byte, names ...string) []byte {
|
||||
b := bytes.NewBuffer(buf[:0])
|
||||
b.WriteByte(labelSep)
|
||||
i, j := 0, 0
|
||||
for i < len(ls) && j < len(names) {
|
||||
if names[j] < ls[i].Name {
|
||||
@@ -200,30 +216,40 @@ func (ls Labels) WithLabels(names ...string) Labels {
|
||||
} else if ls[i].Name < names[j] {
|
||||
i++
|
||||
} else {
|
||||
ret = append(ret, ls[i])
|
||||
if b.Len() > 1 {
|
||||
b.WriteByte(seps[0])
|
||||
}
|
||||
b.WriteString(ls[i].Name)
|
||||
b.WriteByte(seps[0])
|
||||
b.WriteString(ls[i].Value)
|
||||
i++
|
||||
j++
|
||||
}
|
||||
}
|
||||
return ret
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
// WithoutLabels returns a new labels.Labels from ls that contains labels not matching names.
|
||||
// BytesWithoutLabels is just as Bytes(), but only for labels not matching names.
|
||||
// 'names' have to be sorted in ascending order.
|
||||
func (ls Labels) WithoutLabels(names ...string) Labels {
|
||||
ret := make([]Label, 0, len(ls))
|
||||
|
||||
func (ls Labels) BytesWithoutLabels(buf []byte, names ...string) []byte {
|
||||
b := bytes.NewBuffer(buf[:0])
|
||||
b.WriteByte(labelSep)
|
||||
j := 0
|
||||
for i := range ls {
|
||||
for j < len(names) && names[j] < ls[i].Name {
|
||||
j++
|
||||
}
|
||||
if ls[i].Name == MetricName || (j < len(names) && ls[i].Name == names[j]) {
|
||||
if j < len(names) && ls[i].Name == names[j] {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, ls[i])
|
||||
if b.Len() > 1 {
|
||||
b.WriteByte(seps[0])
|
||||
}
|
||||
b.WriteString(ls[i].Name)
|
||||
b.WriteByte(seps[0])
|
||||
b.WriteString(ls[i].Value)
|
||||
}
|
||||
return ret
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
// Copy returns a copy of the labels.
|
||||
@@ -275,6 +301,7 @@ func (ls Labels) WithoutEmpty() Labels {
|
||||
if v.Value != "" {
|
||||
continue
|
||||
}
|
||||
// Do not copy the slice until it's necessary.
|
||||
els := make(Labels, 0, len(ls)-1)
|
||||
for _, v := range ls {
|
||||
if v.Value != "" {
|
||||
@@ -286,13 +313,26 @@ func (ls Labels) WithoutEmpty() Labels {
|
||||
return ls
|
||||
}
|
||||
|
||||
// IsValid checks if the metric name or label names are valid.
|
||||
func (ls Labels) IsValid() bool {
|
||||
for _, l := range ls {
|
||||
if l.Name == model.MetricNameLabel && !model.IsValidMetricName(model.LabelValue(l.Value)) {
|
||||
return false
|
||||
}
|
||||
if !model.LabelName(l.Name).IsValid() || !model.LabelValue(l.Value).IsValid() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns whether the two label sets are equal.
|
||||
func Equal(ls, o Labels) bool {
|
||||
if len(ls) != len(o) {
|
||||
return false
|
||||
}
|
||||
for i, l := range ls {
|
||||
if l.Name != o[i].Name || l.Value != o[i].Value {
|
||||
if l != o[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -308,13 +348,16 @@ func (ls Labels) Map() map[string]string {
|
||||
return m
|
||||
}
|
||||
|
||||
// EmptyLabels returns n empty Labels value, for convenience.
|
||||
func EmptyLabels() Labels {
|
||||
return Labels{}
|
||||
}
|
||||
|
||||
// New returns a sorted Labels from the given labels.
|
||||
// The caller has to guarantee that all label names are unique.
|
||||
func New(ls ...Label) Labels {
|
||||
set := make(Labels, 0, len(ls))
|
||||
for _, l := range ls {
|
||||
set = append(set, l)
|
||||
}
|
||||
set = append(set, ls...)
|
||||
sort.Sort(set)
|
||||
|
||||
return set
|
||||
@@ -334,7 +377,7 @@ func FromStrings(ss ...string) Labels {
|
||||
if len(ss)%2 != 0 {
|
||||
panic("invalid number of strings")
|
||||
}
|
||||
var res Labels
|
||||
res := make(Labels, 0, len(ss)/2)
|
||||
for i := 0; i < len(ss); i += 2 {
|
||||
res = append(res, Label{Name: ss[i], Value: ss[i+1]})
|
||||
}
|
||||
@@ -369,6 +412,49 @@ func Compare(a, b Labels) int {
|
||||
return len(a) - len(b)
|
||||
}
|
||||
|
||||
// Copy labels from b on top of whatever was in ls previously, reusing memory or expanding if needed.
|
||||
func (ls *Labels) CopyFrom(b Labels) {
|
||||
(*ls) = append((*ls)[:0], b...)
|
||||
}
|
||||
|
||||
// IsEmpty returns true if ls represents an empty set of labels.
|
||||
func (ls Labels) IsEmpty() bool {
|
||||
return len(ls) == 0
|
||||
}
|
||||
|
||||
// Range calls f on each label.
|
||||
func (ls Labels) Range(f func(l Label)) {
|
||||
for _, l := range ls {
|
||||
f(l)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate calls f on each label. If f returns a non-nil error, then it returns that error cancelling the iteration.
|
||||
func (ls Labels) Validate(f func(l Label) error) error {
|
||||
for _, l := range ls {
|
||||
if err := f(l); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InternStrings calls intern on every string value inside ls, replacing them with what it returns.
|
||||
func (ls *Labels) InternStrings(intern func(string) string) {
|
||||
for i, l := range *ls {
|
||||
(*ls)[i].Name = intern(l.Name)
|
||||
(*ls)[i].Value = intern(l.Value)
|
||||
}
|
||||
}
|
||||
|
||||
// ReleaseStrings calls release on every string value inside ls.
|
||||
func (ls Labels) ReleaseStrings(release func(string)) {
|
||||
for _, l := range ls {
|
||||
release(l.Name)
|
||||
release(l.Value)
|
||||
}
|
||||
}
|
||||
|
||||
// Builder allows modifying Labels.
|
||||
type Builder struct {
|
||||
base Labels
|
||||
@@ -411,7 +497,21 @@ func (b *Builder) Del(ns ...string) *Builder {
|
||||
return b
|
||||
}
|
||||
|
||||
// Set the name/value pair as a label.
|
||||
// Keep removes all labels from the base except those with the given names.
|
||||
func (b *Builder) Keep(ns ...string) *Builder {
|
||||
Outer:
|
||||
for _, l := range b.base {
|
||||
for _, n := range ns {
|
||||
if l.Name == n {
|
||||
continue Outer
|
||||
}
|
||||
}
|
||||
b.del = append(b.del, l.Name)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Set the name/value pair as a label. A value of "" means delete that label.
|
||||
func (b *Builder) Set(n, v string) *Builder {
|
||||
if v == "" {
|
||||
// Empty labels are the same as missing labels.
|
||||
@@ -428,17 +528,25 @@ func (b *Builder) Set(n, v string) *Builder {
|
||||
return b
|
||||
}
|
||||
|
||||
// Labels returns the labels from the builder. If no modifications
|
||||
// were made, the original labels are returned.
|
||||
func (b *Builder) Labels() Labels {
|
||||
// Labels returns the labels from the builder, adding them to res if non-nil.
|
||||
// Argument res can be the same as b.base, if caller wants to overwrite that slice.
|
||||
// If no modifications were made, the original labels are returned.
|
||||
func (b *Builder) Labels(res Labels) Labels {
|
||||
if len(b.del) == 0 && len(b.add) == 0 {
|
||||
return b.base
|
||||
}
|
||||
|
||||
// In the general case, labels are removed, modified or moved
|
||||
// rather than added.
|
||||
res := make(Labels, 0, len(b.base))
|
||||
if res == nil {
|
||||
// In the general case, labels are removed, modified or moved
|
||||
// rather than added.
|
||||
res = make(Labels, 0, len(b.base))
|
||||
} else {
|
||||
res = res[:0]
|
||||
}
|
||||
Outer:
|
||||
// Justification that res can be the same slice as base: in this loop
|
||||
// we move forward through base, and either skip an element or assign
|
||||
// it to res at its current position or an earlier position.
|
||||
for _, l := range b.base {
|
||||
for _, n := range b.del {
|
||||
if l.Name == n {
|
||||
@@ -452,8 +560,46 @@ Outer:
|
||||
}
|
||||
res = append(res, l)
|
||||
}
|
||||
res = append(res, b.add...)
|
||||
sort.Sort(res)
|
||||
|
||||
if len(b.add) > 0 { // Base is already in order, so we only need to sort if we add to it.
|
||||
res = append(res, b.add...)
|
||||
sort.Sort(res)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// ScratchBuilder allows efficient construction of a Labels from scratch.
|
||||
type ScratchBuilder struct {
|
||||
add Labels
|
||||
}
|
||||
|
||||
// NewScratchBuilder creates a ScratchBuilder initialized for Labels with n entries.
|
||||
func NewScratchBuilder(n int) ScratchBuilder {
|
||||
return ScratchBuilder{add: make([]Label, 0, n)}
|
||||
}
|
||||
|
||||
func (b *ScratchBuilder) Reset() {
|
||||
b.add = b.add[:0]
|
||||
}
|
||||
|
||||
// Add a name/value pair.
|
||||
// Note if you Add the same name twice you will get a duplicate label, which is invalid.
|
||||
func (b *ScratchBuilder) Add(name, value string) {
|
||||
b.add = append(b.add, Label{Name: name, Value: value})
|
||||
}
|
||||
|
||||
// Sort the labels added so far by name.
|
||||
func (b *ScratchBuilder) Sort() {
|
||||
sort.Sort(b.add)
|
||||
}
|
||||
|
||||
// Asssign is for when you already have a Labels which you want this ScratchBuilder to return.
|
||||
func (b *ScratchBuilder) Assign(ls Labels) {
|
||||
b.add = append(b.add[:0], ls...) // Copy on top of our slice, so we don't retain the input slice.
|
||||
}
|
||||
|
||||
// Return the name/value pairs added so far as a Labels object.
|
||||
// Note: if you want them sorted, call Sort() first.
|
||||
func (b *ScratchBuilder) Labels() Labels {
|
||||
// Copy the slice, so the next use of ScratchBuilder doesn't overwrite.
|
||||
return append([]Label{}, b.add...)
|
||||
}
|
||||
@@ -28,17 +28,18 @@ const (
|
||||
MatchNotRegexp
|
||||
)
|
||||
|
||||
var matchTypeToStr = [...]string{
|
||||
MatchEqual: "=",
|
||||
MatchNotEqual: "!=",
|
||||
MatchRegexp: "=~",
|
||||
MatchNotRegexp: "!~",
|
||||
}
|
||||
|
||||
func (m MatchType) String() string {
|
||||
typeToStr := map[MatchType]string{
|
||||
MatchEqual: "=",
|
||||
MatchNotEqual: "!=",
|
||||
MatchRegexp: "=~",
|
||||
MatchNotRegexp: "!~",
|
||||
if m < MatchEqual || m > MatchNotRegexp {
|
||||
panic("unknown match type")
|
||||
}
|
||||
if str, ok := typeToStr[m]; ok {
|
||||
return str
|
||||
}
|
||||
panic("unknown match type")
|
||||
return matchTypeToStr[m]
|
||||
}
|
||||
|
||||
// Matcher models the matching of a label.
|
||||
@@ -14,9 +14,10 @@
|
||||
package labels
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"regexp/syntax"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/grafana/regexp/syntax"
|
||||
)
|
||||
|
||||
type FastRegexMatcher struct {
|
||||
@@ -86,10 +87,10 @@ func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix, contains string) {
|
||||
// Given Prometheus regex matchers are always anchored to the begin/end
|
||||
// of the text, if the first/last operations are literals, we can safely
|
||||
// treat them as prefix/suffix.
|
||||
if sub[0].Op == syntax.OpLiteral {
|
||||
if sub[0].Op == syntax.OpLiteral && (sub[0].Flags&syntax.FoldCase) == 0 {
|
||||
prefix = string(sub[0].Rune)
|
||||
}
|
||||
if last := len(sub) - 1; sub[last].Op == syntax.OpLiteral {
|
||||
if last := len(sub) - 1; sub[last].Op == syntax.OpLiteral && (sub[last].Flags&syntax.FoldCase) == 0 {
|
||||
suffix = string(sub[last].Rune)
|
||||
}
|
||||
|
||||
@@ -97,7 +98,7 @@ func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix, contains string) {
|
||||
// 1st one. We do not keep the whole list of literals to simplify the
|
||||
// fast path.
|
||||
for i := 1; i < len(sub)-1; i++ {
|
||||
if sub[i].Op == syntax.OpLiteral {
|
||||
if sub[i].Op == syntax.OpLiteral && (sub[i].Flags&syntax.FoldCase) == 0 {
|
||||
contains = string(sub[i].Rune)
|
||||
break
|
||||
}
|
||||
@@ -15,11 +15,9 @@ package labels
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Slice is a sortable slice of label sets.
|
||||
@@ -52,13 +50,14 @@ func ReadLabels(fn string, n int) ([]Labels, error) {
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
b := ScratchBuilder{}
|
||||
|
||||
var mets []Labels
|
||||
hashes := map[uint64]struct{}{}
|
||||
i := 0
|
||||
|
||||
for scanner.Scan() && i < n {
|
||||
m := make(Labels, 0, 10)
|
||||
b.Reset()
|
||||
|
||||
r := strings.NewReplacer("\"", "", "{", "", "}", "")
|
||||
s := r.Replace(scanner.Text())
|
||||
@@ -66,10 +65,11 @@ func ReadLabels(fn string, n int) ([]Labels, error) {
|
||||
labelChunks := strings.Split(s, ",")
|
||||
for _, labelChunk := range labelChunks {
|
||||
split := strings.Split(labelChunk, ":")
|
||||
m = append(m, Label{Name: split[0], Value: split[1]})
|
||||
b.Add(split[0], split[1])
|
||||
}
|
||||
// Order of the k/v labels matters, don't assume we'll always receive them already sorted.
|
||||
sort.Sort(m)
|
||||
b.Sort()
|
||||
m := b.Labels()
|
||||
|
||||
h := m.Hash()
|
||||
if _, ok := hashes[h]; ok {
|
||||
@@ -81,7 +81,7 @@ func ReadLabels(fn string, n int) ([]Labels, error) {
|
||||
}
|
||||
|
||||
if i != n {
|
||||
return mets, errors.Errorf("requested %d metrics but found %d", n, i)
|
||||
return mets, fmt.Errorf("requested %d metrics but found %d", n, i)
|
||||
}
|
||||
return mets, nil
|
||||
}
|
||||
23
vendor/github.com/prometheus/prometheus/model/metadata/metadata.go
generated
vendored
Normal file
23
vendor/github.com/prometheus/prometheus/model/metadata/metadata.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2022 The Prometheus Authors
|
||||
// Licensed 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 metadata
|
||||
|
||||
import "github.com/prometheus/prometheus/model/textparse"
|
||||
|
||||
// Metadata stores a series' metadata information.
|
||||
type Metadata struct {
|
||||
Type textparse.MetricType
|
||||
Unit string
|
||||
Help string
|
||||
}
|
||||
309
vendor/github.com/prometheus/prometheus/model/relabel/relabel.go
generated
vendored
Normal file
309
vendor/github.com/prometheus/prometheus/model/relabel/relabel.go
generated
vendored
Normal file
@@ -0,0 +1,309 @@
|
||||
// Copyright 2015 The Prometheus Authors
|
||||
// Licensed 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 relabel
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
)
|
||||
|
||||
var (
|
||||
relabelTarget = regexp.MustCompile(`^(?:(?:[a-zA-Z_]|\$(?:\{\w+\}|\w+))+\w*)+$`)
|
||||
|
||||
DefaultRelabelConfig = Config{
|
||||
Action: Replace,
|
||||
Separator: ";",
|
||||
Regex: MustNewRegexp("(.*)"),
|
||||
Replacement: "$1",
|
||||
}
|
||||
)
|
||||
|
||||
// Action is the action to be performed on relabeling.
|
||||
type Action string
|
||||
|
||||
const (
|
||||
// Replace performs a regex replacement.
|
||||
Replace Action = "replace"
|
||||
// Keep drops targets for which the input does not match the regex.
|
||||
Keep Action = "keep"
|
||||
// Drop drops targets for which the input does match the regex.
|
||||
Drop Action = "drop"
|
||||
// KeepEqual drops targets for which the input does not match the target.
|
||||
KeepEqual Action = "keepequal"
|
||||
// Drop drops targets for which the input does match the target.
|
||||
DropEqual Action = "dropequal"
|
||||
// HashMod sets a label to the modulus of a hash of labels.
|
||||
HashMod Action = "hashmod"
|
||||
// LabelMap copies labels to other labelnames based on a regex.
|
||||
LabelMap Action = "labelmap"
|
||||
// LabelDrop drops any label matching the regex.
|
||||
LabelDrop Action = "labeldrop"
|
||||
// LabelKeep drops any label not matching the regex.
|
||||
LabelKeep Action = "labelkeep"
|
||||
// Lowercase maps input letters to their lower case.
|
||||
Lowercase Action = "lowercase"
|
||||
// Uppercase maps input letters to their upper case.
|
||||
Uppercase Action = "uppercase"
|
||||
)
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (a *Action) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var s string
|
||||
if err := unmarshal(&s); err != nil {
|
||||
return err
|
||||
}
|
||||
switch act := Action(strings.ToLower(s)); act {
|
||||
case Replace, Keep, Drop, HashMod, LabelMap, LabelDrop, LabelKeep, Lowercase, Uppercase, KeepEqual, DropEqual:
|
||||
*a = act
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown relabel action %q", s)
|
||||
}
|
||||
|
||||
// Config is the configuration for relabeling of target label sets.
|
||||
type Config struct {
|
||||
// A list of labels from which values are taken and concatenated
|
||||
// with the configured separator in order.
|
||||
SourceLabels model.LabelNames `yaml:"source_labels,flow,omitempty"`
|
||||
// Separator is the string between concatenated values from the source labels.
|
||||
Separator string `yaml:"separator,omitempty"`
|
||||
// Regex against which the concatenation is matched.
|
||||
Regex Regexp `yaml:"regex,omitempty"`
|
||||
// Modulus to take of the hash of concatenated values from the source labels.
|
||||
Modulus uint64 `yaml:"modulus,omitempty"`
|
||||
// TargetLabel is the label to which the resulting string is written in a replacement.
|
||||
// Regexp interpolation is allowed for the replace action.
|
||||
TargetLabel string `yaml:"target_label,omitempty"`
|
||||
// Replacement is the regex replacement pattern to be used.
|
||||
Replacement string `yaml:"replacement,omitempty"`
|
||||
// Action is the action to be performed for the relabeling.
|
||||
Action Action `yaml:"action,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultRelabelConfig
|
||||
type plain Config
|
||||
if err := unmarshal((*plain)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Regex.Regexp == nil {
|
||||
c.Regex = MustNewRegexp("")
|
||||
}
|
||||
if c.Action == "" {
|
||||
return fmt.Errorf("relabel action cannot be empty")
|
||||
}
|
||||
if c.Modulus == 0 && c.Action == HashMod {
|
||||
return fmt.Errorf("relabel configuration for hashmod requires non-zero modulus")
|
||||
}
|
||||
if (c.Action == Replace || c.Action == HashMod || c.Action == Lowercase || c.Action == Uppercase || c.Action == KeepEqual || c.Action == DropEqual) && c.TargetLabel == "" {
|
||||
return fmt.Errorf("relabel configuration for %s action requires 'target_label' value", c.Action)
|
||||
}
|
||||
if (c.Action == Replace || c.Action == Lowercase || c.Action == Uppercase || c.Action == KeepEqual || c.Action == DropEqual) && !relabelTarget.MatchString(c.TargetLabel) {
|
||||
return fmt.Errorf("%q is invalid 'target_label' for %s action", c.TargetLabel, c.Action)
|
||||
}
|
||||
if (c.Action == Lowercase || c.Action == Uppercase || c.Action == KeepEqual || c.Action == DropEqual) && c.Replacement != DefaultRelabelConfig.Replacement {
|
||||
return fmt.Errorf("'replacement' can not be set for %s action", c.Action)
|
||||
}
|
||||
if c.Action == LabelMap && !relabelTarget.MatchString(c.Replacement) {
|
||||
return fmt.Errorf("%q is invalid 'replacement' for %s action", c.Replacement, c.Action)
|
||||
}
|
||||
if c.Action == HashMod && !model.LabelName(c.TargetLabel).IsValid() {
|
||||
return fmt.Errorf("%q is invalid 'target_label' for %s action", c.TargetLabel, c.Action)
|
||||
}
|
||||
|
||||
if c.Action == DropEqual || c.Action == KeepEqual {
|
||||
if c.Regex != DefaultRelabelConfig.Regex ||
|
||||
c.Modulus != DefaultRelabelConfig.Modulus ||
|
||||
c.Separator != DefaultRelabelConfig.Separator ||
|
||||
c.Replacement != DefaultRelabelConfig.Replacement {
|
||||
return fmt.Errorf("%s action requires only 'source_labels' and `target_label`, and no other fields", c.Action)
|
||||
}
|
||||
}
|
||||
|
||||
if c.Action == LabelDrop || c.Action == LabelKeep {
|
||||
if c.SourceLabels != nil ||
|
||||
c.TargetLabel != DefaultRelabelConfig.TargetLabel ||
|
||||
c.Modulus != DefaultRelabelConfig.Modulus ||
|
||||
c.Separator != DefaultRelabelConfig.Separator ||
|
||||
c.Replacement != DefaultRelabelConfig.Replacement {
|
||||
return fmt.Errorf("%s action requires only 'regex', and no other fields", c.Action)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Regexp encapsulates a regexp.Regexp and makes it YAML marshalable.
|
||||
type Regexp struct {
|
||||
*regexp.Regexp
|
||||
}
|
||||
|
||||
// NewRegexp creates a new anchored Regexp and returns an error if the
|
||||
// passed-in regular expression does not compile.
|
||||
func NewRegexp(s string) (Regexp, error) {
|
||||
regex, err := regexp.Compile("^(?:" + s + ")$")
|
||||
return Regexp{Regexp: regex}, err
|
||||
}
|
||||
|
||||
// MustNewRegexp works like NewRegexp, but panics if the regular expression does not compile.
|
||||
func MustNewRegexp(s string) Regexp {
|
||||
re, err := NewRegexp(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return re
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (re *Regexp) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var s string
|
||||
if err := unmarshal(&s); err != nil {
|
||||
return err
|
||||
}
|
||||
r, err := NewRegexp(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*re = r
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalYAML implements the yaml.Marshaler interface.
|
||||
func (re Regexp) MarshalYAML() (interface{}, error) {
|
||||
if re.String() != "" {
|
||||
return re.String(), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// String returns the original string used to compile the regular expression.
|
||||
func (re Regexp) String() string {
|
||||
str := re.Regexp.String()
|
||||
// Trim the anchor `^(?:` prefix and `)$` suffix.
|
||||
return str[4 : len(str)-2]
|
||||
}
|
||||
|
||||
// Process returns a relabeled copy of the given label set. The relabel configurations
|
||||
// are applied in order of input.
|
||||
// If a label set is dropped, EmptyLabels and false is returned.
|
||||
// May return the input labelSet modified.
|
||||
func Process(lbls labels.Labels, cfgs ...*Config) (ret labels.Labels, keep bool) {
|
||||
lb := labels.NewBuilder(labels.EmptyLabels())
|
||||
for _, cfg := range cfgs {
|
||||
lbls, keep = relabel(lbls, cfg, lb)
|
||||
if !keep {
|
||||
return labels.EmptyLabels(), false
|
||||
}
|
||||
}
|
||||
return lbls, true
|
||||
}
|
||||
|
||||
func relabel(lset labels.Labels, cfg *Config, lb *labels.Builder) (ret labels.Labels, keep bool) {
|
||||
var va [16]string
|
||||
values := va[:0]
|
||||
if len(cfg.SourceLabels) > cap(values) {
|
||||
values = make([]string, 0, len(cfg.SourceLabels))
|
||||
}
|
||||
for _, ln := range cfg.SourceLabels {
|
||||
values = append(values, lset.Get(string(ln)))
|
||||
}
|
||||
val := strings.Join(values, cfg.Separator)
|
||||
|
||||
lb.Reset(lset)
|
||||
|
||||
switch cfg.Action {
|
||||
case Drop:
|
||||
if cfg.Regex.MatchString(val) {
|
||||
return labels.EmptyLabels(), false
|
||||
}
|
||||
case Keep:
|
||||
if !cfg.Regex.MatchString(val) {
|
||||
return labels.EmptyLabels(), false
|
||||
}
|
||||
case DropEqual:
|
||||
if lset.Get(cfg.TargetLabel) == val {
|
||||
return labels.EmptyLabels(), false
|
||||
}
|
||||
case KeepEqual:
|
||||
if lset.Get(cfg.TargetLabel) != val {
|
||||
return labels.EmptyLabels(), false
|
||||
}
|
||||
case Replace:
|
||||
indexes := cfg.Regex.FindStringSubmatchIndex(val)
|
||||
// If there is no match no replacement must take place.
|
||||
if indexes == nil {
|
||||
break
|
||||
}
|
||||
target := model.LabelName(cfg.Regex.ExpandString([]byte{}, cfg.TargetLabel, val, indexes))
|
||||
if !target.IsValid() {
|
||||
lb.Del(cfg.TargetLabel)
|
||||
break
|
||||
}
|
||||
res := cfg.Regex.ExpandString([]byte{}, cfg.Replacement, val, indexes)
|
||||
if len(res) == 0 {
|
||||
lb.Del(cfg.TargetLabel)
|
||||
break
|
||||
}
|
||||
lb.Set(string(target), string(res))
|
||||
case Lowercase:
|
||||
lb.Set(cfg.TargetLabel, strings.ToLower(val))
|
||||
case Uppercase:
|
||||
lb.Set(cfg.TargetLabel, strings.ToUpper(val))
|
||||
case HashMod:
|
||||
mod := sum64(md5.Sum([]byte(val))) % cfg.Modulus
|
||||
lb.Set(cfg.TargetLabel, fmt.Sprintf("%d", mod))
|
||||
case LabelMap:
|
||||
lset.Range(func(l labels.Label) {
|
||||
if cfg.Regex.MatchString(l.Name) {
|
||||
res := cfg.Regex.ReplaceAllString(l.Name, cfg.Replacement)
|
||||
lb.Set(res, l.Value)
|
||||
}
|
||||
})
|
||||
case LabelDrop:
|
||||
lset.Range(func(l labels.Label) {
|
||||
if cfg.Regex.MatchString(l.Name) {
|
||||
lb.Del(l.Name)
|
||||
}
|
||||
})
|
||||
case LabelKeep:
|
||||
lset.Range(func(l labels.Label) {
|
||||
if !cfg.Regex.MatchString(l.Name) {
|
||||
lb.Del(l.Name)
|
||||
}
|
||||
})
|
||||
default:
|
||||
panic(fmt.Errorf("relabel: unknown relabel action type %q", cfg.Action))
|
||||
}
|
||||
|
||||
return lb.Labels(lset), true
|
||||
}
|
||||
|
||||
// sum64 sums the md5 hash to an uint64.
|
||||
func sum64(hash [md5.Size]byte) uint64 {
|
||||
var s uint64
|
||||
|
||||
for i, b := range hash {
|
||||
shift := uint64((md5.Size - i - 1) * 8)
|
||||
|
||||
s |= uint64(b) << shift
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -16,16 +16,17 @@ package rulefmt
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/prometheus/prometheus/pkg/timestamp"
|
||||
"github.com/prometheus/prometheus/model/timestamp"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
"github.com/prometheus/prometheus/template"
|
||||
)
|
||||
@@ -38,6 +39,25 @@ type Error struct {
|
||||
Err WrappedError
|
||||
}
|
||||
|
||||
// Error prints the error message in a formatted string.
|
||||
func (err *Error) Error() string {
|
||||
if err.Err.err == nil {
|
||||
return ""
|
||||
}
|
||||
if err.Err.nodeAlt != nil {
|
||||
return fmt.Sprintf("%d:%d: %d:%d: group %q, rule %d, %q: %v", err.Err.node.Line, err.Err.node.Column, err.Err.nodeAlt.Line, err.Err.nodeAlt.Column, err.Group, err.Rule, err.RuleName, err.Err.err)
|
||||
}
|
||||
if err.Err.node != nil {
|
||||
return fmt.Sprintf("%d:%d: group %q, rule %d, %q: %v", err.Err.node.Line, err.Err.node.Column, err.Group, err.Rule, err.RuleName, err.Err.err)
|
||||
}
|
||||
return fmt.Sprintf("group %q, rule %d, %q: %v", err.Group, err.Rule, err.RuleName, err.Err.err)
|
||||
}
|
||||
|
||||
// Unwrap unpacks wrapped error for use in errors.Is & errors.As.
|
||||
func (err *Error) Unwrap() error {
|
||||
return &err.Err
|
||||
}
|
||||
|
||||
// WrappedError wraps error with the yaml node which can be used to represent
|
||||
// the line and column numbers of the error.
|
||||
type WrappedError struct {
|
||||
@@ -46,13 +66,23 @@ type WrappedError struct {
|
||||
nodeAlt *yaml.Node
|
||||
}
|
||||
|
||||
func (err *Error) Error() string {
|
||||
if err.Err.nodeAlt != nil {
|
||||
return errors.Wrapf(err.Err.err, "%d:%d: %d:%d: group %q, rule %d, %q", err.Err.node.Line, err.Err.node.Column, err.Err.nodeAlt.Line, err.Err.nodeAlt.Column, err.Group, err.Rule, err.RuleName).Error()
|
||||
} else if err.Err.node != nil {
|
||||
return errors.Wrapf(err.Err.err, "%d:%d: group %q, rule %d, %q", err.Err.node.Line, err.Err.node.Column, err.Group, err.Rule, err.RuleName).Error()
|
||||
// Error prints the error message in a formatted string.
|
||||
func (we *WrappedError) Error() string {
|
||||
if we.err == nil {
|
||||
return ""
|
||||
}
|
||||
return errors.Wrapf(err.Err.err, "group %q, rule %d, %q", err.Group, err.Rule, err.RuleName).Error()
|
||||
if we.nodeAlt != nil {
|
||||
return fmt.Sprintf("%d:%d: %d:%d: %v", we.node.Line, we.node.Column, we.nodeAlt.Line, we.nodeAlt.Column, we.err)
|
||||
}
|
||||
if we.node != nil {
|
||||
return fmt.Sprintf("%d:%d: %v", we.node.Line, we.node.Column, we.err)
|
||||
}
|
||||
return we.err.Error()
|
||||
}
|
||||
|
||||
// Unwrap unpacks wrapped error for use in errors.Is & errors.As.
|
||||
func (we *WrappedError) Unwrap() error {
|
||||
return we.err
|
||||
}
|
||||
|
||||
// RuleGroups is a set of rule groups that are typically exposed in a file.
|
||||
@@ -70,20 +100,20 @@ func (g *RuleGroups) Validate(node ruleGroups) (errs []error) {
|
||||
|
||||
for j, g := range g.Groups {
|
||||
if g.Name == "" {
|
||||
errs = append(errs, errors.Errorf("%d:%d: Groupname must not be empty", node.Groups[j].Line, node.Groups[j].Column))
|
||||
errs = append(errs, fmt.Errorf("%d:%d: Groupname must not be empty", node.Groups[j].Line, node.Groups[j].Column))
|
||||
}
|
||||
|
||||
if _, ok := set[g.Name]; ok {
|
||||
errs = append(
|
||||
errs,
|
||||
errors.Errorf("%d:%d: groupname: \"%s\" is repeated in the same file", node.Groups[j].Line, node.Groups[j].Column, g.Name),
|
||||
fmt.Errorf("%d:%d: groupname: \"%s\" is repeated in the same file", node.Groups[j].Line, node.Groups[j].Column, g.Name),
|
||||
)
|
||||
}
|
||||
|
||||
set[g.Name] = struct{}{}
|
||||
|
||||
for i, r := range g.Rules {
|
||||
for _, node := range r.Validate() {
|
||||
for _, node := range g.Rules[i].Validate() {
|
||||
var ruleName yaml.Node
|
||||
if r.Alert.Value != "" {
|
||||
ruleName = r.Alert
|
||||
@@ -107,34 +137,37 @@ func (g *RuleGroups) Validate(node ruleGroups) (errs []error) {
|
||||
type RuleGroup struct {
|
||||
Name string `yaml:"name"`
|
||||
Interval model.Duration `yaml:"interval,omitempty"`
|
||||
Limit int `yaml:"limit,omitempty"`
|
||||
Rules []RuleNode `yaml:"rules"`
|
||||
}
|
||||
|
||||
// Rule describes an alerting or recording rule.
|
||||
type Rule struct {
|
||||
Record string `yaml:"record,omitempty"`
|
||||
Alert string `yaml:"alert,omitempty"`
|
||||
Expr string `yaml:"expr"`
|
||||
For model.Duration `yaml:"for,omitempty"`
|
||||
Labels map[string]string `yaml:"labels,omitempty"`
|
||||
Annotations map[string]string `yaml:"annotations,omitempty"`
|
||||
Record string `yaml:"record,omitempty"`
|
||||
Alert string `yaml:"alert,omitempty"`
|
||||
Expr string `yaml:"expr"`
|
||||
For model.Duration `yaml:"for,omitempty"`
|
||||
KeepFiringFor model.Duration `yaml:"keep_firing_for,omitempty"`
|
||||
Labels map[string]string `yaml:"labels,omitempty"`
|
||||
Annotations map[string]string `yaml:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
// RuleNode adds yaml.v3 layer to support line and column outputs for invalid rules.
|
||||
type RuleNode struct {
|
||||
Record yaml.Node `yaml:"record,omitempty"`
|
||||
Alert yaml.Node `yaml:"alert,omitempty"`
|
||||
Expr yaml.Node `yaml:"expr"`
|
||||
For model.Duration `yaml:"for,omitempty"`
|
||||
Labels map[string]string `yaml:"labels,omitempty"`
|
||||
Annotations map[string]string `yaml:"annotations,omitempty"`
|
||||
Record yaml.Node `yaml:"record,omitempty"`
|
||||
Alert yaml.Node `yaml:"alert,omitempty"`
|
||||
Expr yaml.Node `yaml:"expr"`
|
||||
For model.Duration `yaml:"for,omitempty"`
|
||||
KeepFiringFor model.Duration `yaml:"keep_firing_for,omitempty"`
|
||||
Labels map[string]string `yaml:"labels,omitempty"`
|
||||
Annotations map[string]string `yaml:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
// Validate the rule and return a list of encountered errors.
|
||||
func (r *RuleNode) Validate() (nodes []WrappedError) {
|
||||
if r.Record.Value != "" && r.Alert.Value != "" {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: errors.Errorf("only one of 'record' and 'alert' must be set"),
|
||||
err: fmt.Errorf("only one of 'record' and 'alert' must be set"),
|
||||
node: &r.Record,
|
||||
nodeAlt: &r.Alert,
|
||||
})
|
||||
@@ -142,12 +175,12 @@ func (r *RuleNode) Validate() (nodes []WrappedError) {
|
||||
if r.Record.Value == "" && r.Alert.Value == "" {
|
||||
if r.Record.Value == "0" {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: errors.Errorf("one of 'record' or 'alert' must be set"),
|
||||
err: fmt.Errorf("one of 'record' or 'alert' must be set"),
|
||||
node: &r.Alert,
|
||||
})
|
||||
} else {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: errors.Errorf("one of 'record' or 'alert' must be set"),
|
||||
err: fmt.Errorf("one of 'record' or 'alert' must be set"),
|
||||
node: &r.Record,
|
||||
})
|
||||
}
|
||||
@@ -155,31 +188,37 @@ func (r *RuleNode) Validate() (nodes []WrappedError) {
|
||||
|
||||
if r.Expr.Value == "" {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: errors.Errorf("field 'expr' must be set in rule"),
|
||||
err: fmt.Errorf("field 'expr' must be set in rule"),
|
||||
node: &r.Expr,
|
||||
})
|
||||
} else if _, err := parser.ParseExpr(r.Expr.Value); err != nil {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: errors.Wrapf(err, "could not parse expression"),
|
||||
err: fmt.Errorf("could not parse expression: %w", err),
|
||||
node: &r.Expr,
|
||||
})
|
||||
}
|
||||
if r.Record.Value != "" {
|
||||
if len(r.Annotations) > 0 {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: errors.Errorf("invalid field 'annotations' in recording rule"),
|
||||
err: fmt.Errorf("invalid field 'annotations' in recording rule"),
|
||||
node: &r.Record,
|
||||
})
|
||||
}
|
||||
if r.For != 0 {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: errors.Errorf("invalid field 'for' in recording rule"),
|
||||
err: fmt.Errorf("invalid field 'for' in recording rule"),
|
||||
node: &r.Record,
|
||||
})
|
||||
}
|
||||
if r.KeepFiringFor != 0 {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: fmt.Errorf("invalid field 'keep_firing_for' in recording rule"),
|
||||
node: &r.Record,
|
||||
})
|
||||
}
|
||||
if !model.IsValidMetricName(model.LabelValue(r.Record.Value)) {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: errors.Errorf("invalid recording rule name: %s", r.Record.Value),
|
||||
err: fmt.Errorf("invalid recording rule name: %s", r.Record.Value),
|
||||
node: &r.Record,
|
||||
})
|
||||
}
|
||||
@@ -188,13 +227,13 @@ func (r *RuleNode) Validate() (nodes []WrappedError) {
|
||||
for k, v := range r.Labels {
|
||||
if !model.LabelName(k).IsValid() || k == model.MetricNameLabel {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: errors.Errorf("invalid label name: %s", k),
|
||||
err: fmt.Errorf("invalid label name: %s", k),
|
||||
})
|
||||
}
|
||||
|
||||
if !model.LabelValue(v).IsValid() {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: errors.Errorf("invalid label value: %s", v),
|
||||
err: fmt.Errorf("invalid label value: %s", v),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -202,7 +241,7 @@ func (r *RuleNode) Validate() (nodes []WrappedError) {
|
||||
for k := range r.Annotations {
|
||||
if !model.LabelName(k).IsValid() {
|
||||
nodes = append(nodes, WrappedError{
|
||||
err: errors.Errorf("invalid annotation name: %s", k),
|
||||
err: fmt.Errorf("invalid annotation name: %s", k),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -223,10 +262,11 @@ func testTemplateParsing(rl *RuleNode) (errs []error) {
|
||||
}
|
||||
|
||||
// Trying to parse templates.
|
||||
tmplData := template.AlertTemplateData(map[string]string{}, map[string]string{}, 0)
|
||||
tmplData := template.AlertTemplateData(map[string]string{}, map[string]string{}, "", 0)
|
||||
defs := []string{
|
||||
"{{$labels := .Labels}}",
|
||||
"{{$externalLabels := .ExternalLabels}}",
|
||||
"{{$externalURL := .ExternalURL}}",
|
||||
"{{$value := .Value}}",
|
||||
}
|
||||
parseTest := func(text string) error {
|
||||
@@ -238,6 +278,7 @@ func testTemplateParsing(rl *RuleNode) (errs []error) {
|
||||
model.Time(timestamp.FromTime(time.Now())),
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
return tmpl.ParseTest()
|
||||
}
|
||||
@@ -246,7 +287,7 @@ func testTemplateParsing(rl *RuleNode) (errs []error) {
|
||||
for k, val := range rl.Labels {
|
||||
err := parseTest(val)
|
||||
if err != nil {
|
||||
errs = append(errs, errors.Wrapf(err, "label %q", k))
|
||||
errs = append(errs, fmt.Errorf("label %q: %w", k, err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +295,7 @@ func testTemplateParsing(rl *RuleNode) (errs []error) {
|
||||
for k, val := range rl.Annotations {
|
||||
err := parseTest(val)
|
||||
if err != nil {
|
||||
errs = append(errs, errors.Wrapf(err, "annotation %q", k))
|
||||
errs = append(errs, fmt.Errorf("annotation %q: %w", k, err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +314,7 @@ func Parse(content []byte) (*RuleGroups, []error) {
|
||||
decoder.KnownFields(true)
|
||||
err := decoder.Decode(&groups)
|
||||
// Ignore io.EOF which happens with empty input.
|
||||
if err != nil && err != io.EOF {
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
err = yaml.Unmarshal(content, &node)
|
||||
@@ -290,13 +331,13 @@ func Parse(content []byte) (*RuleGroups, []error) {
|
||||
|
||||
// ParseFile reads and parses rules from a file.
|
||||
func ParseFile(file string) (*RuleGroups, []error) {
|
||||
b, err := ioutil.ReadFile(file)
|
||||
b, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, []error{errors.Wrap(err, file)}
|
||||
return nil, []error{fmt.Errorf("%s: %w", file, err)}
|
||||
}
|
||||
rgs, errs := Parse(b)
|
||||
for i := range errs {
|
||||
errs[i] = errors.Wrap(errs[i], file)
|
||||
errs[i] = fmt.Errorf("%s: %w", file, errs[i])
|
||||
}
|
||||
return rgs, errs
|
||||
}
|
||||
@@ -16,17 +16,24 @@ package textparse
|
||||
import (
|
||||
"mime"
|
||||
|
||||
"github.com/prometheus/prometheus/pkg/exemplar"
|
||||
"github.com/prometheus/prometheus/pkg/labels"
|
||||
"github.com/prometheus/prometheus/model/exemplar"
|
||||
"github.com/prometheus/prometheus/model/histogram"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
)
|
||||
|
||||
// Parser parses samples from a byte slice of samples in the official
|
||||
// Prometheus and OpenMetrics text exposition formats.
|
||||
type Parser interface {
|
||||
// Series returns the bytes of the series, the timestamp if set, and the value
|
||||
// of the current sample.
|
||||
// Series returns the bytes of a series with a simple float64 as a
|
||||
// value, the timestamp if set, and the value of the current sample.
|
||||
Series() ([]byte, *int64, float64)
|
||||
|
||||
// Histogram returns the bytes of a series with a sparse histogram as a
|
||||
// value, the timestamp if set, and the histogram in the current sample.
|
||||
// Depending on the parsed input, the function returns an (integer) Histogram
|
||||
// or a FloatHistogram, with the respective other return value being nil.
|
||||
Histogram() ([]byte, *int64, *histogram.Histogram, *histogram.FloatHistogram)
|
||||
|
||||
// Help returns the metric name and help text in the current entry.
|
||||
// Must only be called after Next returned a help entry.
|
||||
// The returned byte slices become invalid after the next call to Next.
|
||||
@@ -61,36 +68,51 @@ type Parser interface {
|
||||
}
|
||||
|
||||
// New returns a new parser of the byte slice.
|
||||
func New(b []byte, contentType string) Parser {
|
||||
mediaType, _, err := mime.ParseMediaType(contentType)
|
||||
if err == nil && mediaType == "application/openmetrics-text" {
|
||||
return NewOpenMetricsParser(b)
|
||||
//
|
||||
// This function always returns a valid parser, but might additionally
|
||||
// return an error if the content type cannot be parsed.
|
||||
func New(b []byte, contentType string) (Parser, error) {
|
||||
if contentType == "" {
|
||||
return NewPromParser(b), nil
|
||||
}
|
||||
|
||||
mediaType, _, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
return NewPromParser(b), err
|
||||
}
|
||||
switch mediaType {
|
||||
case "application/openmetrics-text":
|
||||
return NewOpenMetricsParser(b), nil
|
||||
case "application/vnd.google.protobuf":
|
||||
return NewProtobufParser(b), nil
|
||||
default:
|
||||
return NewPromParser(b), nil
|
||||
}
|
||||
return NewPromParser(b)
|
||||
}
|
||||
|
||||
// Entry represents the type of a parsed entry.
|
||||
type Entry int
|
||||
|
||||
const (
|
||||
EntryInvalid Entry = -1
|
||||
EntryType Entry = 0
|
||||
EntryHelp Entry = 1
|
||||
EntrySeries Entry = 2
|
||||
EntryComment Entry = 3
|
||||
EntryUnit Entry = 4
|
||||
EntryInvalid Entry = -1
|
||||
EntryType Entry = 0
|
||||
EntryHelp Entry = 1
|
||||
EntrySeries Entry = 2 // A series with a simple float64 as value.
|
||||
EntryComment Entry = 3
|
||||
EntryUnit Entry = 4
|
||||
EntryHistogram Entry = 5 // A series with a sparse histogram as a value.
|
||||
)
|
||||
|
||||
// MetricType represents metric type values.
|
||||
type MetricType string
|
||||
|
||||
const (
|
||||
MetricTypeCounter = "counter"
|
||||
MetricTypeGauge = "gauge"
|
||||
MetricTypeHistogram = "histogram"
|
||||
MetricTypeGaugeHistogram = "gaugehistogram"
|
||||
MetricTypeSummary = "summary"
|
||||
MetricTypeInfo = "info"
|
||||
MetricTypeStateset = "stateset"
|
||||
MetricTypeUnknown = "unknown"
|
||||
MetricTypeCounter = MetricType("counter")
|
||||
MetricTypeGauge = MetricType("gauge")
|
||||
MetricTypeHistogram = MetricType("histogram")
|
||||
MetricTypeGaugeHistogram = MetricType("gaugehistogram")
|
||||
MetricTypeSummary = MetricType("summary")
|
||||
MetricTypeInfo = MetricType("info")
|
||||
MetricTypeStateset = MetricType("stateset")
|
||||
MetricTypeUnknown = MetricType("unknown")
|
||||
)
|
||||
@@ -58,8 +58,6 @@ yystate0:
|
||||
goto yystart61
|
||||
}
|
||||
|
||||
goto yystate0 // silence unused label error
|
||||
goto yystate1 // silence unused label error
|
||||
yystate1:
|
||||
c = l.next()
|
||||
yystart1:
|
||||
@@ -94,7 +92,6 @@ yystate4:
|
||||
goto yystate4
|
||||
}
|
||||
|
||||
goto yystate5 // silence unused label error
|
||||
yystate5:
|
||||
c = l.next()
|
||||
yystart5:
|
||||
@@ -262,7 +259,6 @@ yystate24:
|
||||
c = l.next()
|
||||
goto yyrule4
|
||||
|
||||
goto yystate25 // silence unused label error
|
||||
yystate25:
|
||||
c = l.next()
|
||||
yystart25:
|
||||
@@ -282,7 +278,6 @@ yystate26:
|
||||
goto yystate26
|
||||
}
|
||||
|
||||
goto yystate27 // silence unused label error
|
||||
yystate27:
|
||||
c = l.next()
|
||||
yystart27:
|
||||
@@ -308,7 +303,6 @@ yystate29:
|
||||
c = l.next()
|
||||
goto yyrule7
|
||||
|
||||
goto yystate30 // silence unused label error
|
||||
yystate30:
|
||||
c = l.next()
|
||||
yystart30:
|
||||
@@ -346,7 +340,6 @@ yystate34:
|
||||
c = l.next()
|
||||
goto yyrule11
|
||||
|
||||
goto yystate35 // silence unused label error
|
||||
yystate35:
|
||||
c = l.next()
|
||||
yystart35:
|
||||
@@ -383,7 +376,6 @@ yystate38:
|
||||
goto yystate36
|
||||
}
|
||||
|
||||
goto yystate39 // silence unused label error
|
||||
yystate39:
|
||||
c = l.next()
|
||||
yystart39:
|
||||
@@ -418,7 +410,6 @@ yystate42:
|
||||
c = l.next()
|
||||
goto yyrule9
|
||||
|
||||
goto yystate43 // silence unused label error
|
||||
yystate43:
|
||||
c = l.next()
|
||||
yystart43:
|
||||
@@ -479,7 +470,6 @@ yystate49:
|
||||
c = l.next()
|
||||
goto yyrule18
|
||||
|
||||
goto yystate50 // silence unused label error
|
||||
yystate50:
|
||||
c = l.next()
|
||||
yystart50:
|
||||
@@ -517,7 +507,6 @@ yystate54:
|
||||
c = l.next()
|
||||
goto yyrule20
|
||||
|
||||
goto yystate55 // silence unused label error
|
||||
yystate55:
|
||||
c = l.next()
|
||||
yystart55:
|
||||
@@ -574,7 +563,6 @@ yystate60:
|
||||
goto yystate58
|
||||
}
|
||||
|
||||
goto yystate61 // silence unused label error
|
||||
yystate61:
|
||||
c = l.next()
|
||||
yystart61:
|
||||
@@ -747,16 +735,58 @@ yyrule25: // {S}[^ \n]+
|
||||
return tTimestamp
|
||||
}
|
||||
yyrule26: // \n
|
||||
{
|
||||
if true { // avoid go vet determining the below panic will not be reached
|
||||
l.state = sInit
|
||||
return tLinebreak
|
||||
goto yystate0
|
||||
}
|
||||
panic("unreachable")
|
||||
|
||||
goto yyabort // silence unused label error
|
||||
|
||||
yyabort: // no lexem recognized
|
||||
//
|
||||
// silence unused label errors for build and satisfy go vet reachability analysis
|
||||
//
|
||||
{
|
||||
if false {
|
||||
goto yyabort
|
||||
}
|
||||
if false {
|
||||
goto yystate0
|
||||
}
|
||||
if false {
|
||||
goto yystate1
|
||||
}
|
||||
if false {
|
||||
goto yystate5
|
||||
}
|
||||
if false {
|
||||
goto yystate25
|
||||
}
|
||||
if false {
|
||||
goto yystate27
|
||||
}
|
||||
if false {
|
||||
goto yystate30
|
||||
}
|
||||
if false {
|
||||
goto yystate35
|
||||
}
|
||||
if false {
|
||||
goto yystate39
|
||||
}
|
||||
if false {
|
||||
goto yystate43
|
||||
}
|
||||
if false {
|
||||
goto yystate50
|
||||
}
|
||||
if false {
|
||||
goto yystate55
|
||||
}
|
||||
if false {
|
||||
goto yystate61
|
||||
}
|
||||
}
|
||||
|
||||
return tInvalid
|
||||
}
|
||||
@@ -18,18 +18,17 @@ package textparse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/prometheus/prometheus/pkg/exemplar"
|
||||
"github.com/prometheus/prometheus/pkg/labels"
|
||||
"github.com/prometheus/prometheus/pkg/value"
|
||||
"github.com/prometheus/prometheus/model/exemplar"
|
||||
"github.com/prometheus/prometheus/model/histogram"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/model/value"
|
||||
)
|
||||
|
||||
var allowedSuffixes = [][]byte{[]byte("_total"), []byte("_bucket")}
|
||||
@@ -82,6 +81,7 @@ func (l *openMetricsLexer) Error(es string) {
|
||||
// This is based on the working draft https://docs.google.com/document/u/1/d/1KwV0mAXwwbvvifBvDKH_LU1YjyXE_wxCkHNoCGq1GX0/edit
|
||||
type OpenMetricsParser struct {
|
||||
l *openMetricsLexer
|
||||
builder labels.ScratchBuilder
|
||||
series []byte
|
||||
text []byte
|
||||
mtype MetricType
|
||||
@@ -113,6 +113,12 @@ func (p *OpenMetricsParser) Series() ([]byte, *int64, float64) {
|
||||
return p.series, nil, p.val
|
||||
}
|
||||
|
||||
// Histogram returns (nil, nil, nil, nil) for now because OpenMetrics does not
|
||||
// support sparse histograms yet.
|
||||
func (p *OpenMetricsParser) Histogram() ([]byte, *int64, *histogram.Histogram, *histogram.FloatHistogram) {
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Help returns the metric name and help text in the current entry.
|
||||
// Must only be called after Next returned a help entry.
|
||||
// The returned byte slices become invalid after the next call to Next.
|
||||
@@ -152,14 +158,11 @@ func (p *OpenMetricsParser) Comment() []byte {
|
||||
// Metric writes the labels of the current sample into the passed labels.
|
||||
// It returns the string from which the metric was parsed.
|
||||
func (p *OpenMetricsParser) Metric(l *labels.Labels) string {
|
||||
// Allocate the full immutable string immediately, so we just
|
||||
// have to create references on it below.
|
||||
// Copy the buffer to a string: this is only necessary for the return value.
|
||||
s := string(p.series)
|
||||
|
||||
*l = append(*l, labels.Label{
|
||||
Name: labels.MetricName,
|
||||
Value: s[:p.offsets[0]-p.start],
|
||||
})
|
||||
p.builder.Reset()
|
||||
p.builder.Add(labels.MetricName, s[:p.offsets[0]-p.start])
|
||||
|
||||
for i := 1; i < len(p.offsets); i += 4 {
|
||||
a := p.offsets[i] - p.start
|
||||
@@ -167,17 +170,16 @@ func (p *OpenMetricsParser) Metric(l *labels.Labels) string {
|
||||
c := p.offsets[i+2] - p.start
|
||||
d := p.offsets[i+3] - p.start
|
||||
|
||||
value := s[c:d]
|
||||
// Replacer causes allocations. Replace only when necessary.
|
||||
if strings.IndexByte(s[c:d], byte('\\')) >= 0 {
|
||||
*l = append(*l, labels.Label{Name: s[a:b], Value: lvalReplacer.Replace(s[c:d])})
|
||||
continue
|
||||
value = lvalReplacer.Replace(value)
|
||||
}
|
||||
*l = append(*l, labels.Label{Name: s[a:b], Value: s[c:d]})
|
||||
p.builder.Add(s[a:b], value)
|
||||
}
|
||||
|
||||
// Sort labels. We can skip the first entry since the metric name is
|
||||
// already at the right place.
|
||||
sort.Sort((*l)[1:])
|
||||
p.builder.Sort()
|
||||
*l = p.builder.Labels()
|
||||
|
||||
return s
|
||||
}
|
||||
@@ -199,17 +201,18 @@ func (p *OpenMetricsParser) Exemplar(e *exemplar.Exemplar) bool {
|
||||
e.Ts = p.exemplarTs
|
||||
}
|
||||
|
||||
p.builder.Reset()
|
||||
for i := 0; i < len(p.eOffsets); i += 4 {
|
||||
a := p.eOffsets[i] - p.start
|
||||
b := p.eOffsets[i+1] - p.start
|
||||
c := p.eOffsets[i+2] - p.start
|
||||
d := p.eOffsets[i+3] - p.start
|
||||
|
||||
e.Labels = append(e.Labels, labels.Label{Name: s[a:b], Value: s[c:d]})
|
||||
p.builder.Add(s[a:b], s[c:d])
|
||||
}
|
||||
|
||||
// Sort the labels.
|
||||
sort.Sort(e.Labels)
|
||||
p.builder.Sort()
|
||||
e.Labels = p.builder.Labels()
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -241,13 +244,13 @@ func (p *OpenMetricsParser) Next() (Entry, error) {
|
||||
case tEOF:
|
||||
return EntryInvalid, errors.New("data does not end with # EOF")
|
||||
case tHelp, tType, tUnit:
|
||||
switch t := p.nextToken(); t {
|
||||
switch t2 := p.nextToken(); t2 {
|
||||
case tMName:
|
||||
p.offsets = append(p.offsets, p.l.start, p.l.i)
|
||||
default:
|
||||
return EntryInvalid, parseError("expected metric name after HELP", t)
|
||||
return EntryInvalid, parseError("expected metric name after "+t.String(), t2)
|
||||
}
|
||||
switch t := p.nextToken(); t {
|
||||
switch t2 := p.nextToken(); t2 {
|
||||
case tText:
|
||||
if len(p.l.buf()) > 1 {
|
||||
p.text = p.l.buf()[1 : len(p.l.buf())-1]
|
||||
@@ -255,7 +258,7 @@ func (p *OpenMetricsParser) Next() (Entry, error) {
|
||||
p.text = []byte{}
|
||||
}
|
||||
default:
|
||||
return EntryInvalid, parseError("expected text in HELP", t)
|
||||
return EntryInvalid, fmt.Errorf("expected text in %s", t.String())
|
||||
}
|
||||
switch t {
|
||||
case tType:
|
||||
@@ -277,7 +280,7 @@ func (p *OpenMetricsParser) Next() (Entry, error) {
|
||||
case "unknown":
|
||||
p.mtype = MetricTypeUnknown
|
||||
default:
|
||||
return EntryInvalid, errors.Errorf("invalid metric type %q", s)
|
||||
return EntryInvalid, fmt.Errorf("invalid metric type %q", s)
|
||||
}
|
||||
case tHelp:
|
||||
if !utf8.Valid(p.text) {
|
||||
@@ -294,7 +297,7 @@ func (p *OpenMetricsParser) Next() (Entry, error) {
|
||||
u := yoloString(p.text)
|
||||
if len(u) > 0 {
|
||||
if !strings.HasSuffix(m, u) || len(m) < len(u)+1 || p.l.b[p.offsets[1]-len(u)-1] != '_' {
|
||||
return EntryInvalid, errors.Errorf("unit not a suffix of metric %q", m)
|
||||
return EntryInvalid, fmt.Errorf("unit not a suffix of metric %q", m)
|
||||
}
|
||||
}
|
||||
return EntryUnit, nil
|
||||
@@ -306,11 +309,10 @@ func (p *OpenMetricsParser) Next() (Entry, error) {
|
||||
|
||||
t2 := p.nextToken()
|
||||
if t2 == tBraceOpen {
|
||||
offsets, err := p.parseLVals()
|
||||
p.offsets, err = p.parseLVals(p.offsets)
|
||||
if err != nil {
|
||||
return EntryInvalid, err
|
||||
}
|
||||
p.offsets = append(p.offsets, offsets...)
|
||||
p.series = p.l.b[p.start:p.l.i]
|
||||
t2 = p.nextToken()
|
||||
}
|
||||
@@ -336,6 +338,9 @@ func (p *OpenMetricsParser) Next() (Entry, error) {
|
||||
if ts, err = parseFloat(yoloString(p.l.buf()[1:])); err != nil {
|
||||
return EntryInvalid, err
|
||||
}
|
||||
if math.IsNaN(ts) || math.IsInf(ts, 0) {
|
||||
return EntryInvalid, errors.New("invalid timestamp")
|
||||
}
|
||||
p.ts = int64(ts * 1000)
|
||||
switch t3 := p.nextToken(); t3 {
|
||||
case tLinebreak:
|
||||
@@ -352,7 +357,7 @@ func (p *OpenMetricsParser) Next() (Entry, error) {
|
||||
return EntrySeries, nil
|
||||
|
||||
default:
|
||||
err = errors.Errorf("%q %q is not a valid start token", t, string(p.l.cur()))
|
||||
err = fmt.Errorf("%q %q is not a valid start token", t, string(p.l.cur()))
|
||||
}
|
||||
return EntryInvalid, err
|
||||
}
|
||||
@@ -364,12 +369,12 @@ func (p *OpenMetricsParser) parseComment() error {
|
||||
return err
|
||||
}
|
||||
|
||||
var err error
|
||||
// Parse the labels.
|
||||
offsets, err := p.parseLVals()
|
||||
p.eOffsets, err = p.parseLVals(p.eOffsets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.eOffsets = append(p.eOffsets, offsets...)
|
||||
p.exemplar = p.l.b[p.start:p.l.i]
|
||||
|
||||
// Get the value.
|
||||
@@ -392,6 +397,9 @@ func (p *OpenMetricsParser) parseComment() error {
|
||||
if ts, err = parseFloat(yoloString(p.l.buf()[1:])); err != nil {
|
||||
return err
|
||||
}
|
||||
if math.IsNaN(ts) || math.IsInf(ts, 0) {
|
||||
return errors.New("invalid exemplar timestamp")
|
||||
}
|
||||
p.exemplarTs = int64(ts * 1000)
|
||||
switch t3 := p.nextToken(); t3 {
|
||||
case tLinebreak:
|
||||
@@ -404,8 +412,7 @@ func (p *OpenMetricsParser) parseComment() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *OpenMetricsParser) parseLVals() ([]int, error) {
|
||||
var offsets []int
|
||||
func (p *OpenMetricsParser) parseLVals(offsets []int) ([]int, error) {
|
||||
first := true
|
||||
for {
|
||||
t := p.nextToken()
|
||||
@@ -27,6 +27,9 @@ const (
|
||||
sLValue
|
||||
sValue
|
||||
sTimestamp
|
||||
sExemplar
|
||||
sEValue
|
||||
sETimestamp
|
||||
)
|
||||
|
||||
// Lex is called by the parser generated by "go tool yacc" to obtain each
|
||||
@@ -1,4 +1,4 @@
|
||||
// CAUTION: Generated file - DO NOT EDIT.
|
||||
// Code generated by golex. DO NOT EDIT.
|
||||
|
||||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -16,7 +16,7 @@
|
||||
package textparse
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -47,7 +47,7 @@ yystate0:
|
||||
|
||||
switch yyt := l.state; yyt {
|
||||
default:
|
||||
panic(errors.Errorf(`invalid start condition %d`, yyt))
|
||||
panic(fmt.Errorf(`invalid start condition %d`, yyt))
|
||||
case 0: // start condition: INITIAL
|
||||
goto yystart1
|
||||
case 1: // start condition: sComment
|
||||
@@ -66,8 +66,6 @@ yystate0:
|
||||
goto yystart36
|
||||
}
|
||||
|
||||
goto yystate0 // silence unused label error
|
||||
goto yystate1 // silence unused label error
|
||||
yystate1:
|
||||
c = l.next()
|
||||
yystart1:
|
||||
@@ -130,7 +128,6 @@ yystate7:
|
||||
goto yystate7
|
||||
}
|
||||
|
||||
goto yystate8 // silence unused label error
|
||||
yystate8:
|
||||
c = l.next()
|
||||
yystart8:
|
||||
@@ -235,7 +232,6 @@ yystate18:
|
||||
goto yystate18
|
||||
}
|
||||
|
||||
goto yystate19 // silence unused label error
|
||||
yystate19:
|
||||
c = l.next()
|
||||
yystart19:
|
||||
@@ -257,7 +253,6 @@ yystate20:
|
||||
goto yystate20
|
||||
}
|
||||
|
||||
goto yystate21 // silence unused label error
|
||||
yystate21:
|
||||
c = l.next()
|
||||
yystart21:
|
||||
@@ -290,7 +285,6 @@ yystate23:
|
||||
goto yystate22
|
||||
}
|
||||
|
||||
goto yystate24 // silence unused label error
|
||||
yystate24:
|
||||
c = l.next()
|
||||
yystart24:
|
||||
@@ -330,7 +324,6 @@ yystate28:
|
||||
c = l.next()
|
||||
goto yyrule13
|
||||
|
||||
goto yystate29 // silence unused label error
|
||||
yystate29:
|
||||
c = l.next()
|
||||
yystart29:
|
||||
@@ -369,7 +362,6 @@ yystate32:
|
||||
goto yystate30
|
||||
}
|
||||
|
||||
goto yystate33 // silence unused label error
|
||||
yystate33:
|
||||
c = l.next()
|
||||
yystart33:
|
||||
@@ -397,7 +389,6 @@ yystate35:
|
||||
c = l.next()
|
||||
goto yyrule11
|
||||
|
||||
goto yystate36 // silence unused label error
|
||||
yystate36:
|
||||
c = l.next()
|
||||
yystart36:
|
||||
@@ -521,16 +512,50 @@ yyrule18: // {D}+
|
||||
return tTimestamp
|
||||
}
|
||||
yyrule19: // \n
|
||||
{
|
||||
if true { // avoid go vet determining the below panic will not be reached
|
||||
l.state = sInit
|
||||
return tLinebreak
|
||||
goto yystate0
|
||||
}
|
||||
panic("unreachable")
|
||||
|
||||
goto yyabort // silence unused label error
|
||||
|
||||
yyabort: // no lexem recognized
|
||||
//
|
||||
// silence unused label errors for build and satisfy go vet reachability analysis
|
||||
//
|
||||
{
|
||||
if false {
|
||||
goto yyabort
|
||||
}
|
||||
if false {
|
||||
goto yystate0
|
||||
}
|
||||
if false {
|
||||
goto yystate1
|
||||
}
|
||||
if false {
|
||||
goto yystate8
|
||||
}
|
||||
if false {
|
||||
goto yystate19
|
||||
}
|
||||
if false {
|
||||
goto yystate21
|
||||
}
|
||||
if false {
|
||||
goto yystate24
|
||||
}
|
||||
if false {
|
||||
goto yystate29
|
||||
}
|
||||
if false {
|
||||
goto yystate33
|
||||
}
|
||||
if false {
|
||||
goto yystate36
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround to gobble up comments that started with a HELP or TYPE
|
||||
// prefix. We just consume all characters until we reach a newline.
|
||||
// This saves us from adding disproportionate complexity to the parser.
|
||||
@@ -17,20 +17,19 @@
|
||||
package textparse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/prometheus/prometheus/pkg/exemplar"
|
||||
"github.com/prometheus/prometheus/pkg/labels"
|
||||
"github.com/prometheus/prometheus/pkg/value"
|
||||
"github.com/prometheus/prometheus/model/exemplar"
|
||||
"github.com/prometheus/prometheus/model/histogram"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/model/value"
|
||||
)
|
||||
|
||||
type promlexer struct {
|
||||
@@ -144,6 +143,7 @@ func (l *promlexer) Error(es string) {
|
||||
// Prometheus text exposition format.
|
||||
type PromParser struct {
|
||||
l *promlexer
|
||||
builder labels.ScratchBuilder
|
||||
series []byte
|
||||
text []byte
|
||||
mtype MetricType
|
||||
@@ -168,6 +168,12 @@ func (p *PromParser) Series() ([]byte, *int64, float64) {
|
||||
return p.series, nil, p.val
|
||||
}
|
||||
|
||||
// Histogram returns (nil, nil, nil, nil) for now because the Prometheus text
|
||||
// format does not support sparse histograms yet.
|
||||
func (p *PromParser) Histogram() ([]byte, *int64, *histogram.Histogram, *histogram.FloatHistogram) {
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Help returns the metric name and help text in the current entry.
|
||||
// Must only be called after Next returned a help entry.
|
||||
// The returned byte slices become invalid after the next call to Next.
|
||||
@@ -206,14 +212,11 @@ func (p *PromParser) Comment() []byte {
|
||||
// Metric writes the labels of the current sample into the passed labels.
|
||||
// It returns the string from which the metric was parsed.
|
||||
func (p *PromParser) Metric(l *labels.Labels) string {
|
||||
// Allocate the full immutable string immediately, so we just
|
||||
// have to create references on it below.
|
||||
// Copy the buffer to a string: this is only necessary for the return value.
|
||||
s := string(p.series)
|
||||
|
||||
*l = append(*l, labels.Label{
|
||||
Name: labels.MetricName,
|
||||
Value: s[:p.offsets[0]-p.start],
|
||||
})
|
||||
p.builder.Reset()
|
||||
p.builder.Add(labels.MetricName, s[:p.offsets[0]-p.start])
|
||||
|
||||
for i := 1; i < len(p.offsets); i += 4 {
|
||||
a := p.offsets[i] - p.start
|
||||
@@ -221,16 +224,16 @@ func (p *PromParser) Metric(l *labels.Labels) string {
|
||||
c := p.offsets[i+2] - p.start
|
||||
d := p.offsets[i+3] - p.start
|
||||
|
||||
value := s[c:d]
|
||||
// Replacer causes allocations. Replace only when necessary.
|
||||
if strings.IndexByte(s[c:d], byte('\\')) >= 0 {
|
||||
*l = append(*l, labels.Label{Name: s[a:b], Value: lvalReplacer.Replace(s[c:d])})
|
||||
continue
|
||||
value = lvalReplacer.Replace(value)
|
||||
}
|
||||
*l = append(*l, labels.Label{Name: s[a:b], Value: s[c:d]})
|
||||
p.builder.Add(s[a:b], value)
|
||||
}
|
||||
|
||||
// Sort labels to maintain the sorted labels invariant.
|
||||
sort.Sort(*l)
|
||||
p.builder.Sort()
|
||||
*l = p.builder.Labels()
|
||||
|
||||
return s
|
||||
}
|
||||
@@ -252,7 +255,7 @@ func (p *PromParser) nextToken() token {
|
||||
}
|
||||
|
||||
func parseError(exp string, got token) error {
|
||||
return errors.Errorf("%s, got %q", exp, got)
|
||||
return fmt.Errorf("%s, got %q", exp, got)
|
||||
}
|
||||
|
||||
// Next advances the parser to the next sample. It returns false if no
|
||||
@@ -271,13 +274,13 @@ func (p *PromParser) Next() (Entry, error) {
|
||||
return p.Next()
|
||||
|
||||
case tHelp, tType:
|
||||
switch t := p.nextToken(); t {
|
||||
switch t2 := p.nextToken(); t2 {
|
||||
case tMName:
|
||||
p.offsets = append(p.offsets, p.l.start, p.l.i)
|
||||
default:
|
||||
return EntryInvalid, parseError("expected metric name after HELP", t)
|
||||
return EntryInvalid, parseError("expected metric name after "+t.String(), t2)
|
||||
}
|
||||
switch t := p.nextToken(); t {
|
||||
switch t2 := p.nextToken(); t2 {
|
||||
case tText:
|
||||
if len(p.l.buf()) > 1 {
|
||||
p.text = p.l.buf()[1:]
|
||||
@@ -285,7 +288,7 @@ func (p *PromParser) Next() (Entry, error) {
|
||||
p.text = []byte{}
|
||||
}
|
||||
default:
|
||||
return EntryInvalid, parseError("expected text in HELP", t)
|
||||
return EntryInvalid, fmt.Errorf("expected text in %s", t.String())
|
||||
}
|
||||
switch t {
|
||||
case tType:
|
||||
@@ -301,11 +304,11 @@ func (p *PromParser) Next() (Entry, error) {
|
||||
case "untyped":
|
||||
p.mtype = MetricTypeUnknown
|
||||
default:
|
||||
return EntryInvalid, errors.Errorf("invalid metric type %q", s)
|
||||
return EntryInvalid, fmt.Errorf("invalid metric type %q", s)
|
||||
}
|
||||
case tHelp:
|
||||
if !utf8.Valid(p.text) {
|
||||
return EntryInvalid, errors.Errorf("help text is not a valid utf8 string")
|
||||
return EntryInvalid, fmt.Errorf("help text is not a valid utf8 string")
|
||||
}
|
||||
}
|
||||
if t := p.nextToken(); t != tLinebreak {
|
||||
@@ -337,7 +340,7 @@ func (p *PromParser) Next() (Entry, error) {
|
||||
t2 = p.nextToken()
|
||||
}
|
||||
if t2 != tValue {
|
||||
return EntryInvalid, parseError("expected value after metric", t)
|
||||
return EntryInvalid, parseError("expected value after metric", t2)
|
||||
}
|
||||
if p.val, err = parseFloat(yoloString(p.l.buf())); err != nil {
|
||||
return EntryInvalid, err
|
||||
@@ -347,7 +350,7 @@ func (p *PromParser) Next() (Entry, error) {
|
||||
p.val = math.Float64frombits(value.NormalNaN)
|
||||
}
|
||||
p.hasTS = false
|
||||
switch p.nextToken() {
|
||||
switch t := p.nextToken(); t {
|
||||
case tLinebreak:
|
||||
break
|
||||
case tTimestamp:
|
||||
@@ -356,7 +359,7 @@ func (p *PromParser) Next() (Entry, error) {
|
||||
return EntryInvalid, err
|
||||
}
|
||||
if t2 := p.nextToken(); t2 != tLinebreak {
|
||||
return EntryInvalid, parseError("expected next entry after timestamp", t)
|
||||
return EntryInvalid, parseError("expected next entry after timestamp", t2)
|
||||
}
|
||||
default:
|
||||
return EntryInvalid, parseError("expected timestamp or new record", t)
|
||||
@@ -364,7 +367,7 @@ func (p *PromParser) Next() (Entry, error) {
|
||||
return EntrySeries, nil
|
||||
|
||||
default:
|
||||
err = errors.Errorf("%q is not a valid start token", t)
|
||||
err = fmt.Errorf("%q is not a valid start token", t)
|
||||
}
|
||||
return EntryInvalid, err
|
||||
}
|
||||
@@ -388,7 +391,7 @@ func (p *PromParser) parseLVals() error {
|
||||
return parseError("expected label value", t)
|
||||
}
|
||||
if !utf8.Valid(p.l.buf()) {
|
||||
return errors.Errorf("invalid UTF-8 label value")
|
||||
return fmt.Errorf("invalid UTF-8 label value")
|
||||
}
|
||||
|
||||
// The promlexer ensures the value string is quoted. Strip first
|
||||
538
vendor/github.com/prometheus/prometheus/model/textparse/protobufparse.go
generated
vendored
Normal file
538
vendor/github.com/prometheus/prometheus/model/textparse/protobufparse.go
generated
vendored
Normal file
@@ -0,0 +1,538 @@
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// Licensed 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 textparse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/prometheus/model/exemplar"
|
||||
"github.com/prometheus/prometheus/model/histogram"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
|
||||
dto "github.com/prometheus/prometheus/prompb/io/prometheus/client"
|
||||
)
|
||||
|
||||
// ProtobufParser is a very inefficient way of unmarshaling the old Prometheus
|
||||
// protobuf format and then present it as it if were parsed by a
|
||||
// Prometheus-2-style text parser. This is only done so that we can easily plug
|
||||
// in the protobuf format into Prometheus 2. For future use (with the final
|
||||
// format that will be used for native histograms), we have to revisit the
|
||||
// parsing. A lot of the efficiency tricks of the Prometheus-2-style parsing
|
||||
// could be used in a similar fashion (byte-slice pointers into the raw
|
||||
// payload), which requires some hand-coded protobuf handling. But the current
|
||||
// parsers all expect the full series name (metric name plus label pairs) as one
|
||||
// string, which is not how things are represented in the protobuf format. If
|
||||
// the re-arrangement work is actually causing problems (which has to be seen),
|
||||
// that expectation needs to be changed.
|
||||
type ProtobufParser struct {
|
||||
in []byte // The intput to parse.
|
||||
inPos int // Position within the input.
|
||||
metricPos int // Position within Metric slice.
|
||||
// fieldPos is the position within a Summary or (legacy) Histogram. -2
|
||||
// is the count. -1 is the sum. Otherwise it is the index within
|
||||
// quantiles/buckets.
|
||||
fieldPos int
|
||||
fieldsDone bool // true if no more fields of a Summary or (legacy) Histogram to be processed.
|
||||
// state is marked by the entry we are processing. EntryInvalid implies
|
||||
// that we have to decode the next MetricFamily.
|
||||
state Entry
|
||||
|
||||
builder labels.ScratchBuilder // held here to reduce allocations when building Labels
|
||||
|
||||
mf *dto.MetricFamily
|
||||
|
||||
// The following are just shenanigans to satisfy the Parser interface.
|
||||
metricBytes *bytes.Buffer // A somewhat fluid representation of the current metric.
|
||||
}
|
||||
|
||||
// NewProtobufParser returns a parser for the payload in the byte slice.
|
||||
func NewProtobufParser(b []byte) Parser {
|
||||
return &ProtobufParser{
|
||||
in: b,
|
||||
state: EntryInvalid,
|
||||
mf: &dto.MetricFamily{},
|
||||
metricBytes: &bytes.Buffer{},
|
||||
}
|
||||
}
|
||||
|
||||
// Series returns the bytes of a series with a simple float64 as a
|
||||
// value, the timestamp if set, and the value of the current sample.
|
||||
func (p *ProtobufParser) Series() ([]byte, *int64, float64) {
|
||||
var (
|
||||
m = p.mf.GetMetric()[p.metricPos]
|
||||
ts = m.GetTimestampMs()
|
||||
v float64
|
||||
)
|
||||
switch p.mf.GetType() {
|
||||
case dto.MetricType_COUNTER:
|
||||
v = m.GetCounter().GetValue()
|
||||
case dto.MetricType_GAUGE:
|
||||
v = m.GetGauge().GetValue()
|
||||
case dto.MetricType_UNTYPED:
|
||||
v = m.GetUntyped().GetValue()
|
||||
case dto.MetricType_SUMMARY:
|
||||
s := m.GetSummary()
|
||||
switch p.fieldPos {
|
||||
case -2:
|
||||
v = float64(s.GetSampleCount())
|
||||
case -1:
|
||||
v = s.GetSampleSum()
|
||||
// Need to detect a summaries without quantile here.
|
||||
if len(s.GetQuantile()) == 0 {
|
||||
p.fieldsDone = true
|
||||
}
|
||||
default:
|
||||
v = s.GetQuantile()[p.fieldPos].GetValue()
|
||||
}
|
||||
case dto.MetricType_HISTOGRAM, dto.MetricType_GAUGE_HISTOGRAM:
|
||||
// This should only happen for a legacy histogram.
|
||||
h := m.GetHistogram()
|
||||
switch p.fieldPos {
|
||||
case -2:
|
||||
v = float64(h.GetSampleCount())
|
||||
case -1:
|
||||
v = h.GetSampleSum()
|
||||
default:
|
||||
bb := h.GetBucket()
|
||||
if p.fieldPos >= len(bb) {
|
||||
v = float64(h.GetSampleCount())
|
||||
} else {
|
||||
v = float64(bb[p.fieldPos].GetCumulativeCount())
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic("encountered unexpected metric type, this is a bug")
|
||||
}
|
||||
if ts != 0 {
|
||||
return p.metricBytes.Bytes(), &ts, v
|
||||
}
|
||||
// Nasty hack: Assume that ts==0 means no timestamp. That's not true in
|
||||
// general, but proto3 has no distinction between unset and
|
||||
// default. Need to avoid in the final format.
|
||||
return p.metricBytes.Bytes(), nil, v
|
||||
}
|
||||
|
||||
// Histogram returns the bytes of a series with a native histogram as a value,
|
||||
// the timestamp if set, and the native histogram in the current sample.
|
||||
//
|
||||
// The Compact method is called before returning the Histogram (or FloatHistogram).
|
||||
//
|
||||
// If the SampleCountFloat or the ZeroCountFloat in the proto message is > 0,
|
||||
// the histogram is parsed and returned as a FloatHistogram and nil is returned
|
||||
// as the (integer) Histogram return value. Otherwise, it is parsed and returned
|
||||
// as an (integer) Histogram and nil is returned as the FloatHistogram return
|
||||
// value.
|
||||
func (p *ProtobufParser) Histogram() ([]byte, *int64, *histogram.Histogram, *histogram.FloatHistogram) {
|
||||
var (
|
||||
m = p.mf.GetMetric()[p.metricPos]
|
||||
ts = m.GetTimestampMs()
|
||||
h = m.GetHistogram()
|
||||
)
|
||||
if h.GetSampleCountFloat() > 0 || h.GetZeroCountFloat() > 0 {
|
||||
// It is a float histogram.
|
||||
fh := histogram.FloatHistogram{
|
||||
Count: h.GetSampleCountFloat(),
|
||||
Sum: h.GetSampleSum(),
|
||||
ZeroThreshold: h.GetZeroThreshold(),
|
||||
ZeroCount: h.GetZeroCountFloat(),
|
||||
Schema: h.GetSchema(),
|
||||
PositiveSpans: make([]histogram.Span, len(h.GetPositiveSpan())),
|
||||
PositiveBuckets: h.GetPositiveCount(),
|
||||
NegativeSpans: make([]histogram.Span, len(h.GetNegativeSpan())),
|
||||
NegativeBuckets: h.GetNegativeCount(),
|
||||
}
|
||||
for i, span := range h.GetPositiveSpan() {
|
||||
fh.PositiveSpans[i].Offset = span.GetOffset()
|
||||
fh.PositiveSpans[i].Length = span.GetLength()
|
||||
}
|
||||
for i, span := range h.GetNegativeSpan() {
|
||||
fh.NegativeSpans[i].Offset = span.GetOffset()
|
||||
fh.NegativeSpans[i].Length = span.GetLength()
|
||||
}
|
||||
if p.mf.GetType() == dto.MetricType_GAUGE_HISTOGRAM {
|
||||
fh.CounterResetHint = histogram.GaugeType
|
||||
}
|
||||
fh.Compact(0)
|
||||
if ts != 0 {
|
||||
return p.metricBytes.Bytes(), &ts, nil, &fh
|
||||
}
|
||||
// Nasty hack: Assume that ts==0 means no timestamp. That's not true in
|
||||
// general, but proto3 has no distinction between unset and
|
||||
// default. Need to avoid in the final format.
|
||||
return p.metricBytes.Bytes(), nil, nil, &fh
|
||||
}
|
||||
|
||||
sh := histogram.Histogram{
|
||||
Count: h.GetSampleCount(),
|
||||
Sum: h.GetSampleSum(),
|
||||
ZeroThreshold: h.GetZeroThreshold(),
|
||||
ZeroCount: h.GetZeroCount(),
|
||||
Schema: h.GetSchema(),
|
||||
PositiveSpans: make([]histogram.Span, len(h.GetPositiveSpan())),
|
||||
PositiveBuckets: h.GetPositiveDelta(),
|
||||
NegativeSpans: make([]histogram.Span, len(h.GetNegativeSpan())),
|
||||
NegativeBuckets: h.GetNegativeDelta(),
|
||||
}
|
||||
for i, span := range h.GetPositiveSpan() {
|
||||
sh.PositiveSpans[i].Offset = span.GetOffset()
|
||||
sh.PositiveSpans[i].Length = span.GetLength()
|
||||
}
|
||||
for i, span := range h.GetNegativeSpan() {
|
||||
sh.NegativeSpans[i].Offset = span.GetOffset()
|
||||
sh.NegativeSpans[i].Length = span.GetLength()
|
||||
}
|
||||
if p.mf.GetType() == dto.MetricType_GAUGE_HISTOGRAM {
|
||||
sh.CounterResetHint = histogram.GaugeType
|
||||
}
|
||||
sh.Compact(0)
|
||||
if ts != 0 {
|
||||
return p.metricBytes.Bytes(), &ts, &sh, nil
|
||||
}
|
||||
return p.metricBytes.Bytes(), nil, &sh, nil
|
||||
}
|
||||
|
||||
// Help returns the metric name and help text in the current entry.
|
||||
// Must only be called after Next returned a help entry.
|
||||
// The returned byte slices become invalid after the next call to Next.
|
||||
func (p *ProtobufParser) Help() ([]byte, []byte) {
|
||||
return p.metricBytes.Bytes(), []byte(p.mf.GetHelp())
|
||||
}
|
||||
|
||||
// Type returns the metric name and type in the current entry.
|
||||
// Must only be called after Next returned a type entry.
|
||||
// The returned byte slices become invalid after the next call to Next.
|
||||
func (p *ProtobufParser) Type() ([]byte, MetricType) {
|
||||
n := p.metricBytes.Bytes()
|
||||
switch p.mf.GetType() {
|
||||
case dto.MetricType_COUNTER:
|
||||
return n, MetricTypeCounter
|
||||
case dto.MetricType_GAUGE:
|
||||
return n, MetricTypeGauge
|
||||
case dto.MetricType_HISTOGRAM:
|
||||
return n, MetricTypeHistogram
|
||||
case dto.MetricType_GAUGE_HISTOGRAM:
|
||||
return n, MetricTypeGaugeHistogram
|
||||
case dto.MetricType_SUMMARY:
|
||||
return n, MetricTypeSummary
|
||||
}
|
||||
return n, MetricTypeUnknown
|
||||
}
|
||||
|
||||
// Unit always returns (nil, nil) because units aren't supported by the protobuf
|
||||
// format.
|
||||
func (p *ProtobufParser) Unit() ([]byte, []byte) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Comment always returns nil because comments aren't supported by the protobuf
|
||||
// format.
|
||||
func (p *ProtobufParser) Comment() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Metric writes the labels of the current sample into the passed labels.
|
||||
// It returns the string from which the metric was parsed.
|
||||
func (p *ProtobufParser) Metric(l *labels.Labels) string {
|
||||
p.builder.Reset()
|
||||
p.builder.Add(labels.MetricName, p.getMagicName())
|
||||
|
||||
for _, lp := range p.mf.GetMetric()[p.metricPos].GetLabel() {
|
||||
p.builder.Add(lp.GetName(), lp.GetValue())
|
||||
}
|
||||
if needed, name, value := p.getMagicLabel(); needed {
|
||||
p.builder.Add(name, value)
|
||||
}
|
||||
|
||||
// Sort labels to maintain the sorted labels invariant.
|
||||
p.builder.Sort()
|
||||
*l = p.builder.Labels()
|
||||
|
||||
return p.metricBytes.String()
|
||||
}
|
||||
|
||||
// Exemplar writes the exemplar of the current sample into the passed
|
||||
// exemplar. It returns if an exemplar exists or not. In case of a native
|
||||
// histogram, the legacy bucket section is still used for exemplars. To ingest
|
||||
// all examplars, call the Exemplar method repeatedly until it returns false.
|
||||
func (p *ProtobufParser) Exemplar(ex *exemplar.Exemplar) bool {
|
||||
m := p.mf.GetMetric()[p.metricPos]
|
||||
var exProto *dto.Exemplar
|
||||
switch p.mf.GetType() {
|
||||
case dto.MetricType_COUNTER:
|
||||
exProto = m.GetCounter().GetExemplar()
|
||||
case dto.MetricType_HISTOGRAM, dto.MetricType_GAUGE_HISTOGRAM:
|
||||
bb := m.GetHistogram().GetBucket()
|
||||
if p.fieldPos < 0 {
|
||||
if p.state == EntrySeries {
|
||||
return false // At _count or _sum.
|
||||
}
|
||||
p.fieldPos = 0 // Start at 1st bucket for native histograms.
|
||||
}
|
||||
for p.fieldPos < len(bb) {
|
||||
exProto = bb[p.fieldPos].GetExemplar()
|
||||
if p.state == EntrySeries {
|
||||
break
|
||||
}
|
||||
p.fieldPos++
|
||||
if exProto != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
if exProto == nil {
|
||||
return false
|
||||
}
|
||||
ex.Value = exProto.GetValue()
|
||||
if ts := exProto.GetTimestamp(); ts != nil {
|
||||
ex.HasTs = true
|
||||
ex.Ts = ts.GetSeconds()*1000 + int64(ts.GetNanos()/1_000_000)
|
||||
}
|
||||
p.builder.Reset()
|
||||
for _, lp := range exProto.GetLabel() {
|
||||
p.builder.Add(lp.GetName(), lp.GetValue())
|
||||
}
|
||||
p.builder.Sort()
|
||||
ex.Labels = p.builder.Labels()
|
||||
return true
|
||||
}
|
||||
|
||||
// Next advances the parser to the next "sample" (emulating the behavior of a
|
||||
// text format parser). It returns (EntryInvalid, io.EOF) if no samples were
|
||||
// read.
|
||||
func (p *ProtobufParser) Next() (Entry, error) {
|
||||
switch p.state {
|
||||
case EntryInvalid:
|
||||
p.metricPos = 0
|
||||
p.fieldPos = -2
|
||||
n, err := readDelimited(p.in[p.inPos:], p.mf)
|
||||
p.inPos += n
|
||||
if err != nil {
|
||||
return p.state, err
|
||||
}
|
||||
|
||||
// Skip empty metric families.
|
||||
if len(p.mf.GetMetric()) == 0 {
|
||||
return p.Next()
|
||||
}
|
||||
|
||||
// We are at the beginning of a metric family. Put only the name
|
||||
// into metricBytes and validate only name, help, and type for now.
|
||||
name := p.mf.GetName()
|
||||
if !model.IsValidMetricName(model.LabelValue(name)) {
|
||||
return EntryInvalid, errors.Errorf("invalid metric name: %s", name)
|
||||
}
|
||||
if help := p.mf.GetHelp(); !utf8.ValidString(help) {
|
||||
return EntryInvalid, errors.Errorf("invalid help for metric %q: %s", name, help)
|
||||
}
|
||||
switch p.mf.GetType() {
|
||||
case dto.MetricType_COUNTER,
|
||||
dto.MetricType_GAUGE,
|
||||
dto.MetricType_HISTOGRAM,
|
||||
dto.MetricType_GAUGE_HISTOGRAM,
|
||||
dto.MetricType_SUMMARY,
|
||||
dto.MetricType_UNTYPED:
|
||||
// All good.
|
||||
default:
|
||||
return EntryInvalid, errors.Errorf("unknown metric type for metric %q: %s", name, p.mf.GetType())
|
||||
}
|
||||
p.metricBytes.Reset()
|
||||
p.metricBytes.WriteString(name)
|
||||
|
||||
p.state = EntryHelp
|
||||
case EntryHelp:
|
||||
p.state = EntryType
|
||||
case EntryType:
|
||||
t := p.mf.GetType()
|
||||
if (t == dto.MetricType_HISTOGRAM || t == dto.MetricType_GAUGE_HISTOGRAM) &&
|
||||
isNativeHistogram(p.mf.GetMetric()[0].GetHistogram()) {
|
||||
p.state = EntryHistogram
|
||||
} else {
|
||||
p.state = EntrySeries
|
||||
}
|
||||
if err := p.updateMetricBytes(); err != nil {
|
||||
return EntryInvalid, err
|
||||
}
|
||||
case EntryHistogram, EntrySeries:
|
||||
t := p.mf.GetType()
|
||||
if p.state == EntrySeries && !p.fieldsDone &&
|
||||
(t == dto.MetricType_SUMMARY ||
|
||||
t == dto.MetricType_HISTOGRAM ||
|
||||
t == dto.MetricType_GAUGE_HISTOGRAM) {
|
||||
p.fieldPos++
|
||||
} else {
|
||||
p.metricPos++
|
||||
p.fieldPos = -2
|
||||
p.fieldsDone = false
|
||||
}
|
||||
if p.metricPos >= len(p.mf.GetMetric()) {
|
||||
p.state = EntryInvalid
|
||||
return p.Next()
|
||||
}
|
||||
if err := p.updateMetricBytes(); err != nil {
|
||||
return EntryInvalid, err
|
||||
}
|
||||
default:
|
||||
return EntryInvalid, errors.Errorf("invalid protobuf parsing state: %d", p.state)
|
||||
}
|
||||
return p.state, nil
|
||||
}
|
||||
|
||||
func (p *ProtobufParser) updateMetricBytes() error {
|
||||
b := p.metricBytes
|
||||
b.Reset()
|
||||
b.WriteString(p.getMagicName())
|
||||
for _, lp := range p.mf.GetMetric()[p.metricPos].GetLabel() {
|
||||
b.WriteByte(model.SeparatorByte)
|
||||
n := lp.GetName()
|
||||
if !model.LabelName(n).IsValid() {
|
||||
return errors.Errorf("invalid label name: %s", n)
|
||||
}
|
||||
b.WriteString(n)
|
||||
b.WriteByte(model.SeparatorByte)
|
||||
v := lp.GetValue()
|
||||
if !utf8.ValidString(v) {
|
||||
return errors.Errorf("invalid label value: %s", v)
|
||||
}
|
||||
b.WriteString(v)
|
||||
}
|
||||
if needed, n, v := p.getMagicLabel(); needed {
|
||||
b.WriteByte(model.SeparatorByte)
|
||||
b.WriteString(n)
|
||||
b.WriteByte(model.SeparatorByte)
|
||||
b.WriteString(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getMagicName usually just returns p.mf.GetType() but adds a magic suffix
|
||||
// ("_count", "_sum", "_bucket") if needed according to the current parser
|
||||
// state.
|
||||
func (p *ProtobufParser) getMagicName() string {
|
||||
t := p.mf.GetType()
|
||||
if p.state == EntryHistogram || (t != dto.MetricType_HISTOGRAM && t != dto.MetricType_SUMMARY) {
|
||||
return p.mf.GetName()
|
||||
}
|
||||
if p.fieldPos == -2 {
|
||||
return p.mf.GetName() + "_count"
|
||||
}
|
||||
if p.fieldPos == -1 {
|
||||
return p.mf.GetName() + "_sum"
|
||||
}
|
||||
if t == dto.MetricType_HISTOGRAM || t == dto.MetricType_GAUGE_HISTOGRAM {
|
||||
return p.mf.GetName() + "_bucket"
|
||||
}
|
||||
return p.mf.GetName()
|
||||
}
|
||||
|
||||
// getMagicLabel returns if a magic label ("quantile" or "le") is needed and, if
|
||||
// so, its name and value. It also sets p.fieldsDone if applicable.
|
||||
func (p *ProtobufParser) getMagicLabel() (bool, string, string) {
|
||||
if p.state == EntryHistogram || p.fieldPos < 0 {
|
||||
return false, "", ""
|
||||
}
|
||||
switch p.mf.GetType() {
|
||||
case dto.MetricType_SUMMARY:
|
||||
qq := p.mf.GetMetric()[p.metricPos].GetSummary().GetQuantile()
|
||||
q := qq[p.fieldPos]
|
||||
p.fieldsDone = p.fieldPos == len(qq)-1
|
||||
return true, model.QuantileLabel, formatOpenMetricsFloat(q.GetQuantile())
|
||||
case dto.MetricType_HISTOGRAM, dto.MetricType_GAUGE_HISTOGRAM:
|
||||
bb := p.mf.GetMetric()[p.metricPos].GetHistogram().GetBucket()
|
||||
if p.fieldPos >= len(bb) {
|
||||
p.fieldsDone = true
|
||||
return true, model.BucketLabel, "+Inf"
|
||||
}
|
||||
b := bb[p.fieldPos]
|
||||
p.fieldsDone = math.IsInf(b.GetUpperBound(), +1)
|
||||
return true, model.BucketLabel, formatOpenMetricsFloat(b.GetUpperBound())
|
||||
}
|
||||
return false, "", ""
|
||||
}
|
||||
|
||||
var errInvalidVarint = errors.New("protobufparse: invalid varint encountered")
|
||||
|
||||
// readDelimited is essentially doing what the function of the same name in
|
||||
// github.com/matttproud/golang_protobuf_extensions/pbutil is doing, but it is
|
||||
// specific to a MetricFamily, utilizes the more efficient gogo-protobuf
|
||||
// unmarshaling, and acts on a byte slice directly without any additional
|
||||
// staging buffers.
|
||||
func readDelimited(b []byte, mf *dto.MetricFamily) (n int, err error) {
|
||||
if len(b) == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
messageLength, varIntLength := proto.DecodeVarint(b)
|
||||
if varIntLength == 0 || varIntLength > binary.MaxVarintLen32 {
|
||||
return 0, errInvalidVarint
|
||||
}
|
||||
totalLength := varIntLength + int(messageLength)
|
||||
if totalLength > len(b) {
|
||||
return 0, errors.Errorf("protobufparse: insufficient length of buffer, expected at least %d bytes, got %d bytes", totalLength, len(b))
|
||||
}
|
||||
mf.Reset()
|
||||
return totalLength, mf.Unmarshal(b[varIntLength:totalLength])
|
||||
}
|
||||
|
||||
// formatOpenMetricsFloat works like the usual Go string formatting of a fleat
|
||||
// but appends ".0" if the resulting number would otherwise contain neither a
|
||||
// "." nor an "e".
|
||||
func formatOpenMetricsFloat(f float64) string {
|
||||
// A few common cases hardcoded.
|
||||
switch {
|
||||
case f == 1:
|
||||
return "1.0"
|
||||
case f == 0:
|
||||
return "0.0"
|
||||
case f == -1:
|
||||
return "-1.0"
|
||||
case math.IsNaN(f):
|
||||
return "NaN"
|
||||
case math.IsInf(f, +1):
|
||||
return "+Inf"
|
||||
case math.IsInf(f, -1):
|
||||
return "-Inf"
|
||||
}
|
||||
s := fmt.Sprint(f)
|
||||
if strings.ContainsAny(s, "e.") {
|
||||
return s
|
||||
}
|
||||
return s + ".0"
|
||||
}
|
||||
|
||||
// isNativeHistogram returns false iff the provided histograms has no sparse
|
||||
// buckets and a zero threshold of 0 and a zero count of 0. In principle, this
|
||||
// could still be meant to be a native histogram (with a zero threshold of 0 and
|
||||
// no observations yet), but for now, we'll treat this case as a conventional
|
||||
// histogram.
|
||||
//
|
||||
// TODO(beorn7): In the final format, there should be an unambiguous way of
|
||||
// deciding if a histogram should be ingested as a conventional one or a native
|
||||
// one.
|
||||
func isNativeHistogram(h *dto.Histogram) bool {
|
||||
return len(h.GetNegativeDelta()) > 0 ||
|
||||
len(h.GetPositiveDelta()) > 0 ||
|
||||
h.GetZeroCount() > 0 ||
|
||||
h.GetZeroThreshold() > 0
|
||||
}
|
||||
@@ -13,7 +13,10 @@
|
||||
|
||||
package timestamp
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
// FromTime returns a new millisecond timestamp from a time.
|
||||
func FromTime(t time.Time) int64 {
|
||||
@@ -24,3 +27,8 @@ func FromTime(t time.Time) int64 {
|
||||
func Time(ts int64) time.Time {
|
||||
return time.Unix(ts/1000, (ts%1000)*int64(time.Millisecond)).UTC()
|
||||
}
|
||||
|
||||
// FromFloatSeconds returns a millisecond timestamp from float seconds.
|
||||
func FromFloatSeconds(ts float64) int64 {
|
||||
return int64(math.Round(ts * 1000))
|
||||
}
|
||||
736
vendor/github.com/prometheus/prometheus/notifier/notifier.go
generated
vendored
Normal file
736
vendor/github.com/prometheus/prometheus/notifier/notifier.go
generated
vendored
Normal file
@@ -0,0 +1,736 @@
|
||||
// Copyright 2013 The Prometheus Authors
|
||||
// Licensed 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 notifier
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
config_util "github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/version"
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/prometheus/prometheus/config"
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/model/relabel"
|
||||
)
|
||||
|
||||
const (
|
||||
contentTypeJSON = "application/json"
|
||||
)
|
||||
|
||||
// String constants for instrumentation.
|
||||
const (
|
||||
namespace = "prometheus"
|
||||
subsystem = "notifications"
|
||||
alertmanagerLabel = "alertmanager"
|
||||
)
|
||||
|
||||
var userAgent = fmt.Sprintf("Prometheus/%s", version.Version)
|
||||
|
||||
// Alert is a generic representation of an alert in the Prometheus eco-system.
|
||||
type Alert struct {
|
||||
// Label value pairs for purpose of aggregation, matching, and disposition
|
||||
// dispatching. This must minimally include an "alertname" label.
|
||||
Labels labels.Labels `json:"labels"`
|
||||
|
||||
// Extra key/value information which does not define alert identity.
|
||||
Annotations labels.Labels `json:"annotations"`
|
||||
|
||||
// The known time range for this alert. Both ends are optional.
|
||||
StartsAt time.Time `json:"startsAt,omitempty"`
|
||||
EndsAt time.Time `json:"endsAt,omitempty"`
|
||||
GeneratorURL string `json:"generatorURL,omitempty"`
|
||||
}
|
||||
|
||||
// Name returns the name of the alert. It is equivalent to the "alertname" label.
|
||||
func (a *Alert) Name() string {
|
||||
return a.Labels.Get(labels.AlertName)
|
||||
}
|
||||
|
||||
// Hash returns a hash over the alert. It is equivalent to the alert labels hash.
|
||||
func (a *Alert) Hash() uint64 {
|
||||
return a.Labels.Hash()
|
||||
}
|
||||
|
||||
func (a *Alert) String() string {
|
||||
s := fmt.Sprintf("%s[%s]", a.Name(), fmt.Sprintf("%016x", a.Hash())[:7])
|
||||
if a.Resolved() {
|
||||
return s + "[resolved]"
|
||||
}
|
||||
return s + "[active]"
|
||||
}
|
||||
|
||||
// Resolved returns true iff the activity interval ended in the past.
|
||||
func (a *Alert) Resolved() bool {
|
||||
return a.ResolvedAt(time.Now())
|
||||
}
|
||||
|
||||
// ResolvedAt returns true iff the activity interval ended before
|
||||
// the given timestamp.
|
||||
func (a *Alert) ResolvedAt(ts time.Time) bool {
|
||||
if a.EndsAt.IsZero() {
|
||||
return false
|
||||
}
|
||||
return !a.EndsAt.After(ts)
|
||||
}
|
||||
|
||||
// Manager is responsible for dispatching alert notifications to an
|
||||
// alert manager service.
|
||||
type Manager struct {
|
||||
queue []*Alert
|
||||
opts *Options
|
||||
|
||||
metrics *alertMetrics
|
||||
|
||||
more chan struct{}
|
||||
mtx sync.RWMutex
|
||||
ctx context.Context
|
||||
cancel func()
|
||||
|
||||
alertmanagers map[string]*alertmanagerSet
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// Options are the configurable parameters of a Handler.
|
||||
type Options struct {
|
||||
QueueCapacity int
|
||||
ExternalLabels labels.Labels
|
||||
RelabelConfigs []*relabel.Config
|
||||
// Used for sending HTTP requests to the Alertmanager.
|
||||
Do func(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error)
|
||||
|
||||
Registerer prometheus.Registerer
|
||||
}
|
||||
|
||||
type alertMetrics struct {
|
||||
latency *prometheus.SummaryVec
|
||||
errors *prometheus.CounterVec
|
||||
sent *prometheus.CounterVec
|
||||
dropped prometheus.Counter
|
||||
queueLength prometheus.GaugeFunc
|
||||
queueCapacity prometheus.Gauge
|
||||
alertmanagersDiscovered prometheus.GaugeFunc
|
||||
}
|
||||
|
||||
func newAlertMetrics(r prometheus.Registerer, queueCap int, queueLen, alertmanagersDiscovered func() float64) *alertMetrics {
|
||||
m := &alertMetrics{
|
||||
latency: prometheus.NewSummaryVec(prometheus.SummaryOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "latency_seconds",
|
||||
Help: "Latency quantiles for sending alert notifications.",
|
||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||
},
|
||||
[]string{alertmanagerLabel},
|
||||
),
|
||||
errors: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "errors_total",
|
||||
Help: "Total number of errors sending alert notifications.",
|
||||
},
|
||||
[]string{alertmanagerLabel},
|
||||
),
|
||||
sent: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "sent_total",
|
||||
Help: "Total number of alerts sent.",
|
||||
},
|
||||
[]string{alertmanagerLabel},
|
||||
),
|
||||
dropped: prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "dropped_total",
|
||||
Help: "Total number of alerts dropped due to errors when sending to Alertmanager.",
|
||||
}),
|
||||
queueLength: prometheus.NewGaugeFunc(prometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "queue_length",
|
||||
Help: "The number of alert notifications in the queue.",
|
||||
}, queueLen),
|
||||
queueCapacity: prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "queue_capacity",
|
||||
Help: "The capacity of the alert notifications queue.",
|
||||
}),
|
||||
alertmanagersDiscovered: prometheus.NewGaugeFunc(prometheus.GaugeOpts{
|
||||
Name: "prometheus_notifications_alertmanagers_discovered",
|
||||
Help: "The number of alertmanagers discovered and active.",
|
||||
}, alertmanagersDiscovered),
|
||||
}
|
||||
|
||||
m.queueCapacity.Set(float64(queueCap))
|
||||
|
||||
if r != nil {
|
||||
r.MustRegister(
|
||||
m.latency,
|
||||
m.errors,
|
||||
m.sent,
|
||||
m.dropped,
|
||||
m.queueLength,
|
||||
m.queueCapacity,
|
||||
m.alertmanagersDiscovered,
|
||||
)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
|
||||
if client == nil {
|
||||
client = http.DefaultClient
|
||||
}
|
||||
return client.Do(req.WithContext(ctx))
|
||||
}
|
||||
|
||||
// NewManager is the manager constructor.
|
||||
func NewManager(o *Options, logger log.Logger) *Manager {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
if o.Do == nil {
|
||||
o.Do = do
|
||||
}
|
||||
if logger == nil {
|
||||
logger = log.NewNopLogger()
|
||||
}
|
||||
|
||||
n := &Manager{
|
||||
queue: make([]*Alert, 0, o.QueueCapacity),
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
more: make(chan struct{}, 1),
|
||||
opts: o,
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
queueLenFunc := func() float64 { return float64(n.queueLen()) }
|
||||
alertmanagersDiscoveredFunc := func() float64 { return float64(len(n.Alertmanagers())) }
|
||||
|
||||
n.metrics = newAlertMetrics(
|
||||
o.Registerer,
|
||||
o.QueueCapacity,
|
||||
queueLenFunc,
|
||||
alertmanagersDiscoveredFunc,
|
||||
)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// ApplyConfig updates the status state as the new config requires.
|
||||
func (n *Manager) ApplyConfig(conf *config.Config) error {
|
||||
n.mtx.Lock()
|
||||
defer n.mtx.Unlock()
|
||||
|
||||
n.opts.ExternalLabels = conf.GlobalConfig.ExternalLabels
|
||||
n.opts.RelabelConfigs = conf.AlertingConfig.AlertRelabelConfigs
|
||||
|
||||
amSets := make(map[string]*alertmanagerSet)
|
||||
|
||||
for k, cfg := range conf.AlertingConfig.AlertmanagerConfigs.ToMap() {
|
||||
ams, err := newAlertmanagerSet(cfg, n.logger, n.metrics)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
amSets[k] = ams
|
||||
}
|
||||
|
||||
n.alertmanagers = amSets
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const maxBatchSize = 64
|
||||
|
||||
func (n *Manager) queueLen() int {
|
||||
n.mtx.RLock()
|
||||
defer n.mtx.RUnlock()
|
||||
|
||||
return len(n.queue)
|
||||
}
|
||||
|
||||
func (n *Manager) nextBatch() []*Alert {
|
||||
n.mtx.Lock()
|
||||
defer n.mtx.Unlock()
|
||||
|
||||
var alerts []*Alert
|
||||
|
||||
if len(n.queue) > maxBatchSize {
|
||||
alerts = append(make([]*Alert, 0, maxBatchSize), n.queue[:maxBatchSize]...)
|
||||
n.queue = n.queue[maxBatchSize:]
|
||||
} else {
|
||||
alerts = append(make([]*Alert, 0, len(n.queue)), n.queue...)
|
||||
n.queue = n.queue[:0]
|
||||
}
|
||||
|
||||
return alerts
|
||||
}
|
||||
|
||||
// Run dispatches notifications continuously.
|
||||
func (n *Manager) Run(tsets <-chan map[string][]*targetgroup.Group) {
|
||||
for {
|
||||
// The select is split in two parts, such as we will first try to read
|
||||
// new alertmanager targets if they are available, before sending new
|
||||
// alerts.
|
||||
select {
|
||||
case <-n.ctx.Done():
|
||||
return
|
||||
case ts := <-tsets:
|
||||
n.reload(ts)
|
||||
default:
|
||||
select {
|
||||
case <-n.ctx.Done():
|
||||
return
|
||||
case ts := <-tsets:
|
||||
n.reload(ts)
|
||||
case <-n.more:
|
||||
}
|
||||
}
|
||||
alerts := n.nextBatch()
|
||||
|
||||
if !n.sendAll(alerts...) {
|
||||
n.metrics.dropped.Add(float64(len(alerts)))
|
||||
}
|
||||
// If the queue still has items left, kick off the next iteration.
|
||||
if n.queueLen() > 0 {
|
||||
n.setMore()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Manager) reload(tgs map[string][]*targetgroup.Group) {
|
||||
n.mtx.Lock()
|
||||
defer n.mtx.Unlock()
|
||||
|
||||
for id, tgroup := range tgs {
|
||||
am, ok := n.alertmanagers[id]
|
||||
if !ok {
|
||||
level.Error(n.logger).Log("msg", "couldn't sync alert manager set", "err", fmt.Sprintf("invalid id:%v", id))
|
||||
continue
|
||||
}
|
||||
am.sync(tgroup)
|
||||
}
|
||||
}
|
||||
|
||||
// Send queues the given notification requests for processing.
|
||||
// Panics if called on a handler that is not running.
|
||||
func (n *Manager) Send(alerts ...*Alert) {
|
||||
n.mtx.Lock()
|
||||
defer n.mtx.Unlock()
|
||||
|
||||
// Attach external labels before relabelling and sending.
|
||||
for _, a := range alerts {
|
||||
lb := labels.NewBuilder(a.Labels)
|
||||
|
||||
n.opts.ExternalLabels.Range(func(l labels.Label) {
|
||||
if a.Labels.Get(l.Name) == "" {
|
||||
lb.Set(l.Name, l.Value)
|
||||
}
|
||||
})
|
||||
|
||||
a.Labels = lb.Labels(a.Labels)
|
||||
}
|
||||
|
||||
alerts = n.relabelAlerts(alerts)
|
||||
if len(alerts) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Queue capacity should be significantly larger than a single alert
|
||||
// batch could be.
|
||||
if d := len(alerts) - n.opts.QueueCapacity; d > 0 {
|
||||
alerts = alerts[d:]
|
||||
|
||||
level.Warn(n.logger).Log("msg", "Alert batch larger than queue capacity, dropping alerts", "num_dropped", d)
|
||||
n.metrics.dropped.Add(float64(d))
|
||||
}
|
||||
|
||||
// If the queue is full, remove the oldest alerts in favor
|
||||
// of newer ones.
|
||||
if d := (len(n.queue) + len(alerts)) - n.opts.QueueCapacity; d > 0 {
|
||||
n.queue = n.queue[d:]
|
||||
|
||||
level.Warn(n.logger).Log("msg", "Alert notification queue full, dropping alerts", "num_dropped", d)
|
||||
n.metrics.dropped.Add(float64(d))
|
||||
}
|
||||
n.queue = append(n.queue, alerts...)
|
||||
|
||||
// Notify sending goroutine that there are alerts to be processed.
|
||||
n.setMore()
|
||||
}
|
||||
|
||||
func (n *Manager) relabelAlerts(alerts []*Alert) []*Alert {
|
||||
var relabeledAlerts []*Alert
|
||||
|
||||
for _, alert := range alerts {
|
||||
labels, keep := relabel.Process(alert.Labels, n.opts.RelabelConfigs...)
|
||||
if keep {
|
||||
alert.Labels = labels
|
||||
relabeledAlerts = append(relabeledAlerts, alert)
|
||||
}
|
||||
}
|
||||
return relabeledAlerts
|
||||
}
|
||||
|
||||
// setMore signals that the alert queue has items.
|
||||
func (n *Manager) setMore() {
|
||||
// If we cannot send on the channel, it means the signal already exists
|
||||
// and has not been consumed yet.
|
||||
select {
|
||||
case n.more <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// Alertmanagers returns a slice of Alertmanager URLs.
|
||||
func (n *Manager) Alertmanagers() []*url.URL {
|
||||
n.mtx.RLock()
|
||||
amSets := n.alertmanagers
|
||||
n.mtx.RUnlock()
|
||||
|
||||
var res []*url.URL
|
||||
|
||||
for _, ams := range amSets {
|
||||
ams.mtx.RLock()
|
||||
for _, am := range ams.ams {
|
||||
res = append(res, am.url())
|
||||
}
|
||||
ams.mtx.RUnlock()
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// DroppedAlertmanagers returns a slice of Alertmanager URLs.
|
||||
func (n *Manager) DroppedAlertmanagers() []*url.URL {
|
||||
n.mtx.RLock()
|
||||
amSets := n.alertmanagers
|
||||
n.mtx.RUnlock()
|
||||
|
||||
var res []*url.URL
|
||||
|
||||
for _, ams := range amSets {
|
||||
ams.mtx.RLock()
|
||||
for _, dam := range ams.droppedAms {
|
||||
res = append(res, dam.url())
|
||||
}
|
||||
ams.mtx.RUnlock()
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// sendAll sends the alerts to all configured Alertmanagers concurrently.
|
||||
// It returns true if the alerts could be sent successfully to at least one Alertmanager.
|
||||
func (n *Manager) sendAll(alerts ...*Alert) bool {
|
||||
if len(alerts) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
begin := time.Now()
|
||||
|
||||
// v1Payload and v2Payload represent 'alerts' marshaled for Alertmanager API
|
||||
// v1 or v2. Marshaling happens below. Reference here is for caching between
|
||||
// for loop iterations.
|
||||
var v1Payload, v2Payload []byte
|
||||
|
||||
n.mtx.RLock()
|
||||
amSets := n.alertmanagers
|
||||
n.mtx.RUnlock()
|
||||
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
numSuccess atomic.Uint64
|
||||
)
|
||||
for _, ams := range amSets {
|
||||
var (
|
||||
payload []byte
|
||||
err error
|
||||
)
|
||||
|
||||
ams.mtx.RLock()
|
||||
|
||||
switch ams.cfg.APIVersion {
|
||||
case config.AlertmanagerAPIVersionV1:
|
||||
{
|
||||
if v1Payload == nil {
|
||||
v1Payload, err = json.Marshal(alerts)
|
||||
if err != nil {
|
||||
level.Error(n.logger).Log("msg", "Encoding alerts for Alertmanager API v1 failed", "err", err)
|
||||
ams.mtx.RUnlock()
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
payload = v1Payload
|
||||
}
|
||||
case config.AlertmanagerAPIVersionV2:
|
||||
{
|
||||
if v2Payload == nil {
|
||||
openAPIAlerts := alertsToOpenAPIAlerts(alerts)
|
||||
|
||||
v2Payload, err = json.Marshal(openAPIAlerts)
|
||||
if err != nil {
|
||||
level.Error(n.logger).Log("msg", "Encoding alerts for Alertmanager API v2 failed", "err", err)
|
||||
ams.mtx.RUnlock()
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
payload = v2Payload
|
||||
}
|
||||
default:
|
||||
{
|
||||
level.Error(n.logger).Log(
|
||||
"msg", fmt.Sprintf("Invalid Alertmanager API version '%v', expected one of '%v'", ams.cfg.APIVersion, config.SupportedAlertmanagerAPIVersions),
|
||||
"err", err,
|
||||
)
|
||||
ams.mtx.RUnlock()
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for _, am := range ams.ams {
|
||||
wg.Add(1)
|
||||
|
||||
ctx, cancel := context.WithTimeout(n.ctx, time.Duration(ams.cfg.Timeout))
|
||||
defer cancel()
|
||||
|
||||
go func(client *http.Client, url string) {
|
||||
if err := n.sendOne(ctx, client, url, payload); err != nil {
|
||||
level.Error(n.logger).Log("alertmanager", url, "count", len(alerts), "msg", "Error sending alert", "err", err)
|
||||
n.metrics.errors.WithLabelValues(url).Inc()
|
||||
} else {
|
||||
numSuccess.Inc()
|
||||
}
|
||||
n.metrics.latency.WithLabelValues(url).Observe(time.Since(begin).Seconds())
|
||||
n.metrics.sent.WithLabelValues(url).Add(float64(len(alerts)))
|
||||
|
||||
wg.Done()
|
||||
}(ams.client, am.url().String())
|
||||
}
|
||||
|
||||
ams.mtx.RUnlock()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return numSuccess.Load() > 0
|
||||
}
|
||||
|
||||
func alertsToOpenAPIAlerts(alerts []*Alert) models.PostableAlerts {
|
||||
openAPIAlerts := models.PostableAlerts{}
|
||||
for _, a := range alerts {
|
||||
start := strfmt.DateTime(a.StartsAt)
|
||||
end := strfmt.DateTime(a.EndsAt)
|
||||
openAPIAlerts = append(openAPIAlerts, &models.PostableAlert{
|
||||
Annotations: labelsToOpenAPILabelSet(a.Annotations),
|
||||
EndsAt: end,
|
||||
StartsAt: start,
|
||||
Alert: models.Alert{
|
||||
GeneratorURL: strfmt.URI(a.GeneratorURL),
|
||||
Labels: labelsToOpenAPILabelSet(a.Labels),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return openAPIAlerts
|
||||
}
|
||||
|
||||
func labelsToOpenAPILabelSet(modelLabelSet labels.Labels) models.LabelSet {
|
||||
apiLabelSet := models.LabelSet{}
|
||||
modelLabelSet.Range(func(label labels.Label) {
|
||||
apiLabelSet[label.Name] = label.Value
|
||||
})
|
||||
|
||||
return apiLabelSet
|
||||
}
|
||||
|
||||
func (n *Manager) sendOne(ctx context.Context, c *http.Client, url string, b []byte) error {
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
req.Header.Set("Content-Type", contentTypeJSON)
|
||||
resp, err := n.opts.Do(ctx, c, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
}()
|
||||
|
||||
// Any HTTP status 2xx is OK.
|
||||
if resp.StatusCode/100 != 2 {
|
||||
return fmt.Errorf("bad response status %s", resp.Status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop shuts down the notification handler.
|
||||
func (n *Manager) Stop() {
|
||||
level.Info(n.logger).Log("msg", "Stopping notification manager...")
|
||||
n.cancel()
|
||||
}
|
||||
|
||||
// Alertmanager holds Alertmanager endpoint information.
|
||||
type alertmanager interface {
|
||||
url() *url.URL
|
||||
}
|
||||
|
||||
type alertmanagerLabels struct{ labels.Labels }
|
||||
|
||||
const pathLabel = "__alerts_path__"
|
||||
|
||||
func (a alertmanagerLabels) url() *url.URL {
|
||||
return &url.URL{
|
||||
Scheme: a.Get(model.SchemeLabel),
|
||||
Host: a.Get(model.AddressLabel),
|
||||
Path: a.Get(pathLabel),
|
||||
}
|
||||
}
|
||||
|
||||
// alertmanagerSet contains a set of Alertmanagers discovered via a group of service
|
||||
// discovery definitions that have a common configuration on how alerts should be sent.
|
||||
type alertmanagerSet struct {
|
||||
cfg *config.AlertmanagerConfig
|
||||
client *http.Client
|
||||
|
||||
metrics *alertMetrics
|
||||
|
||||
mtx sync.RWMutex
|
||||
ams []alertmanager
|
||||
droppedAms []alertmanager
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func newAlertmanagerSet(cfg *config.AlertmanagerConfig, logger log.Logger, metrics *alertMetrics) (*alertmanagerSet, error) {
|
||||
client, err := config_util.NewClientFromConfig(cfg.HTTPClientConfig, "alertmanager")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &alertmanagerSet{
|
||||
client: client,
|
||||
cfg: cfg,
|
||||
logger: logger,
|
||||
metrics: metrics,
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// sync extracts a deduplicated set of Alertmanager endpoints from a list
|
||||
// of target groups definitions.
|
||||
func (s *alertmanagerSet) sync(tgs []*targetgroup.Group) {
|
||||
allAms := []alertmanager{}
|
||||
allDroppedAms := []alertmanager{}
|
||||
|
||||
for _, tg := range tgs {
|
||||
ams, droppedAms, err := AlertmanagerFromGroup(tg, s.cfg)
|
||||
if err != nil {
|
||||
level.Error(s.logger).Log("msg", "Creating discovered Alertmanagers failed", "err", err)
|
||||
continue
|
||||
}
|
||||
allAms = append(allAms, ams...)
|
||||
allDroppedAms = append(allDroppedAms, droppedAms...)
|
||||
}
|
||||
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
// Set new Alertmanagers and deduplicate them along their unique URL.
|
||||
s.ams = []alertmanager{}
|
||||
s.droppedAms = []alertmanager{}
|
||||
s.droppedAms = append(s.droppedAms, allDroppedAms...)
|
||||
seen := map[string]struct{}{}
|
||||
|
||||
for _, am := range allAms {
|
||||
us := am.url().String()
|
||||
if _, ok := seen[us]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// This will initialize the Counters for the AM to 0.
|
||||
s.metrics.sent.WithLabelValues(us)
|
||||
s.metrics.errors.WithLabelValues(us)
|
||||
|
||||
seen[us] = struct{}{}
|
||||
s.ams = append(s.ams, am)
|
||||
}
|
||||
}
|
||||
|
||||
func postPath(pre string, v config.AlertmanagerAPIVersion) string {
|
||||
alertPushEndpoint := fmt.Sprintf("/api/%v/alerts", string(v))
|
||||
return path.Join("/", pre, alertPushEndpoint)
|
||||
}
|
||||
|
||||
// AlertmanagerFromGroup extracts a list of alertmanagers from a target group
|
||||
// and an associated AlertmanagerConfig.
|
||||
func AlertmanagerFromGroup(tg *targetgroup.Group, cfg *config.AlertmanagerConfig) ([]alertmanager, []alertmanager, error) {
|
||||
var res []alertmanager
|
||||
var droppedAlertManagers []alertmanager
|
||||
|
||||
for _, tlset := range tg.Targets {
|
||||
lbls := make([]labels.Label, 0, len(tlset)+2+len(tg.Labels))
|
||||
|
||||
for ln, lv := range tlset {
|
||||
lbls = append(lbls, labels.Label{Name: string(ln), Value: string(lv)})
|
||||
}
|
||||
// Set configured scheme as the initial scheme label for overwrite.
|
||||
lbls = append(lbls, labels.Label{Name: model.SchemeLabel, Value: cfg.Scheme})
|
||||
lbls = append(lbls, labels.Label{Name: pathLabel, Value: postPath(cfg.PathPrefix, cfg.APIVersion)})
|
||||
|
||||
// Combine target labels with target group labels.
|
||||
for ln, lv := range tg.Labels {
|
||||
if _, ok := tlset[ln]; !ok {
|
||||
lbls = append(lbls, labels.Label{Name: string(ln), Value: string(lv)})
|
||||
}
|
||||
}
|
||||
|
||||
lset, keep := relabel.Process(labels.New(lbls...), cfg.RelabelConfigs...)
|
||||
if !keep {
|
||||
droppedAlertManagers = append(droppedAlertManagers, alertmanagerLabels{labels.New(lbls...)})
|
||||
continue
|
||||
}
|
||||
|
||||
addr := lset.Get(model.AddressLabel)
|
||||
if err := config.CheckTargetAddress(model.LabelValue(addr)); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
res = append(res, alertmanagerLabels{lset})
|
||||
}
|
||||
return res, droppedAlertManagers, nil
|
||||
}
|
||||
3994
vendor/github.com/prometheus/prometheus/prompb/io/prometheus/client/metrics.pb.go
generated
vendored
Normal file
3994
vendor/github.com/prometheus/prometheus/prompb/io/prometheus/client/metrics.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
146
vendor/github.com/prometheus/prometheus/prompb/io/prometheus/client/metrics.proto
generated
vendored
Normal file
146
vendor/github.com/prometheus/prometheus/prompb/io/prometheus/client/metrics.proto
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright 2013 Prometheus Team
|
||||
// Licensed 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.
|
||||
|
||||
// This is copied and lightly edited from
|
||||
// github.com/prometheus/client_model/io/prometheus/client/metrics.proto
|
||||
// and finally converted to proto3 syntax to make it usable for the
|
||||
// gogo-protobuf approach taken within prometheus/prometheus.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package io.prometheus.client;
|
||||
option go_package = "io_prometheus_client";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
message LabelPair {
|
||||
string name = 1;
|
||||
string value = 2;
|
||||
}
|
||||
|
||||
enum MetricType {
|
||||
// COUNTER must use the Metric field "counter".
|
||||
COUNTER = 0;
|
||||
// GAUGE must use the Metric field "gauge".
|
||||
GAUGE = 1;
|
||||
// SUMMARY must use the Metric field "summary".
|
||||
SUMMARY = 2;
|
||||
// UNTYPED must use the Metric field "untyped".
|
||||
UNTYPED = 3;
|
||||
// HISTOGRAM must use the Metric field "histogram".
|
||||
HISTOGRAM = 4;
|
||||
// GAUGE_HISTOGRAM must use the Metric field "histogram".
|
||||
GAUGE_HISTOGRAM = 5;
|
||||
}
|
||||
|
||||
message Gauge {
|
||||
double value = 1;
|
||||
}
|
||||
|
||||
message Counter {
|
||||
double value = 1;
|
||||
Exemplar exemplar = 2;
|
||||
}
|
||||
|
||||
message Quantile {
|
||||
double quantile = 1;
|
||||
double value = 2;
|
||||
}
|
||||
|
||||
message Summary {
|
||||
uint64 sample_count = 1;
|
||||
double sample_sum = 2;
|
||||
repeated Quantile quantile = 3;
|
||||
}
|
||||
|
||||
message Untyped {
|
||||
double value = 1;
|
||||
}
|
||||
|
||||
message Histogram {
|
||||
uint64 sample_count = 1;
|
||||
double sample_count_float = 4; // Overrides sample_count if > 0.
|
||||
double sample_sum = 2;
|
||||
// Buckets for the conventional histogram.
|
||||
repeated Bucket bucket = 3; // Ordered in increasing order of upper_bound, +Inf bucket is optional.
|
||||
|
||||
// Everything below here is for native histograms (also known as sparse histograms).
|
||||
// Native histograms are an experimental feature without stability guarantees.
|
||||
|
||||
// schema defines the bucket schema. Currently, valid numbers are -4 <= n <= 8.
|
||||
// They are all for base-2 bucket schemas, where 1 is a bucket boundary in each case, and
|
||||
// then each power of two is divided into 2^n logarithmic buckets.
|
||||
// Or in other words, each bucket boundary is the previous boundary times 2^(2^-n).
|
||||
// In the future, more bucket schemas may be added using numbers < -4 or > 8.
|
||||
sint32 schema = 5;
|
||||
double zero_threshold = 6; // Breadth of the zero bucket.
|
||||
uint64 zero_count = 7; // Count in zero bucket.
|
||||
double zero_count_float = 8; // Overrides sb_zero_count if > 0.
|
||||
|
||||
// Negative buckets for the native histogram.
|
||||
repeated BucketSpan negative_span = 9;
|
||||
// Use either "negative_delta" or "negative_count", the former for
|
||||
// regular histograms with integer counts, the latter for float
|
||||
// histograms.
|
||||
repeated sint64 negative_delta = 10; // Count delta of each bucket compared to previous one (or to zero for 1st bucket).
|
||||
repeated double negative_count = 11; // Absolute count of each bucket.
|
||||
|
||||
// Positive buckets for the native histogram.
|
||||
repeated BucketSpan positive_span = 12;
|
||||
// Use either "positive_delta" or "positive_count", the former for
|
||||
// regular histograms with integer counts, the latter for float
|
||||
// histograms.
|
||||
repeated sint64 positive_delta = 13; // Count delta of each bucket compared to previous one (or to zero for 1st bucket).
|
||||
repeated double positive_count = 14; // Absolute count of each bucket.
|
||||
}
|
||||
|
||||
message Bucket {
|
||||
uint64 cumulative_count = 1; // Cumulative in increasing order.
|
||||
double cumulative_count_float = 4; // Overrides cumulative_count if > 0.
|
||||
double upper_bound = 2; // Inclusive.
|
||||
Exemplar exemplar = 3;
|
||||
}
|
||||
|
||||
// A BucketSpan defines a number of consecutive buckets in a native
|
||||
// histogram with their offset. Logically, it would be more
|
||||
// straightforward to include the bucket counts in the Span. However,
|
||||
// the protobuf representation is more compact in the way the data is
|
||||
// structured here (with all the buckets in a single array separate
|
||||
// from the Spans).
|
||||
message BucketSpan {
|
||||
sint32 offset = 1; // Gap to previous span, or starting point for 1st span (which can be negative).
|
||||
uint32 length = 2; // Length of consecutive buckets.
|
||||
}
|
||||
|
||||
message Exemplar {
|
||||
repeated LabelPair label = 1;
|
||||
double value = 2;
|
||||
google.protobuf.Timestamp timestamp = 3; // OpenMetrics-style.
|
||||
}
|
||||
|
||||
message Metric {
|
||||
repeated LabelPair label = 1;
|
||||
Gauge gauge = 2;
|
||||
Counter counter = 3;
|
||||
Summary summary = 4;
|
||||
Untyped untyped = 5;
|
||||
Histogram histogram = 7;
|
||||
int64 timestamp_ms = 6;
|
||||
}
|
||||
|
||||
message MetricFamily {
|
||||
string name = 1;
|
||||
string help = 2;
|
||||
MetricType type = 3;
|
||||
repeated Metric metric = 4;
|
||||
}
|
||||
1357
vendor/github.com/prometheus/prometheus/promql/engine.go
generated
vendored
1357
vendor/github.com/prometheus/prometheus/promql/engine.go
generated
vendored
File diff suppressed because it is too large
Load Diff
575
vendor/github.com/prometheus/prometheus/promql/functions.go
generated
vendored
575
vendor/github.com/prometheus/prometheus/promql/functions.go
generated
vendored
@@ -14,34 +14,41 @@
|
||||
package promql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/prometheus/pkg/labels"
|
||||
"github.com/prometheus/prometheus/model/histogram"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
)
|
||||
|
||||
// FunctionCall is the type of a PromQL function implementation
|
||||
//
|
||||
// vals is a list of the evaluated arguments for the function call.
|
||||
// For range vectors it will be a Matrix with one series, instant vectors a
|
||||
// Vector, scalars a Vector with one series whose value is the scalar
|
||||
// value,and nil for strings.
|
||||
//
|
||||
// For range vectors it will be a Matrix with one series, instant vectors a
|
||||
// Vector, scalars a Vector with one series whose value is the scalar
|
||||
// value,and nil for strings.
|
||||
//
|
||||
// args are the original arguments to the function, where you can access
|
||||
// matrixSelectors, vectorSelectors, and StringLiterals.
|
||||
// matrixSelectors, vectorSelectors, and StringLiterals.
|
||||
//
|
||||
// enh.Out is a pre-allocated empty vector that you may use to accumulate
|
||||
// output before returning it. The vectors in vals should not be returned.a
|
||||
// output before returning it. The vectors in vals should not be returned.a
|
||||
//
|
||||
// Range vector functions need only return a vector with the right value,
|
||||
// the metric and timestamp are not needed.
|
||||
// the metric and timestamp are not needed.
|
||||
//
|
||||
// Instant vector functions need only return a vector with the right values and
|
||||
// metrics, the timestamp are not needed.
|
||||
// metrics, the timestamp are not needed.
|
||||
//
|
||||
// Scalar results should be returned as the value of a sample in a Vector.
|
||||
type FunctionCall func(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector
|
||||
|
||||
@@ -56,14 +63,15 @@ func funcTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper)
|
||||
// It calculates the rate (allowing for counter resets if isCounter is true),
|
||||
// extrapolates if the first/last sample is close to the boundary, and returns
|
||||
// the result as either per-second (if isRate is true) or overall.
|
||||
func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper, isCounter bool, isRate bool) Vector {
|
||||
func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper, isCounter, isRate bool) Vector {
|
||||
ms := args[0].(*parser.MatrixSelector)
|
||||
vs := ms.VectorSelector.(*parser.VectorSelector)
|
||||
|
||||
var (
|
||||
samples = vals[0].(Matrix)[0]
|
||||
rangeStart = enh.Ts - durationMilliseconds(ms.Range+vs.Offset)
|
||||
rangeEnd = enh.Ts - durationMilliseconds(vs.Offset)
|
||||
samples = vals[0].(Matrix)[0]
|
||||
rangeStart = enh.Ts - durationMilliseconds(ms.Range+vs.Offset)
|
||||
rangeEnd = enh.Ts - durationMilliseconds(vs.Offset)
|
||||
resultValue float64
|
||||
resultHistogram *histogram.FloatHistogram
|
||||
)
|
||||
|
||||
// No sense in trying to compute a rate without at least two points. Drop
|
||||
@@ -71,17 +79,35 @@ func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNod
|
||||
if len(samples.Points) < 2 {
|
||||
return enh.Out
|
||||
}
|
||||
var (
|
||||
counterCorrection float64
|
||||
lastValue float64
|
||||
)
|
||||
for _, sample := range samples.Points {
|
||||
if isCounter && sample.V < lastValue {
|
||||
counterCorrection += lastValue
|
||||
|
||||
if samples.Points[0].H != nil {
|
||||
resultHistogram = histogramRate(samples.Points, isCounter)
|
||||
if resultHistogram == nil {
|
||||
// Points are a mix of floats and histograms, or the histograms
|
||||
// are not compatible with each other.
|
||||
// TODO(beorn7): find a way of communicating the exact reason
|
||||
return enh.Out
|
||||
}
|
||||
} else {
|
||||
resultValue = samples.Points[len(samples.Points)-1].V - samples.Points[0].V
|
||||
prevValue := samples.Points[0].V
|
||||
// We have to iterate through everything even in the non-counter
|
||||
// case because we have to check that everything is a float.
|
||||
// TODO(beorn7): Find a way to check that earlier, e.g. by
|
||||
// handing in a []FloatPoint and a []HistogramPoint separately.
|
||||
for _, currPoint := range samples.Points[1:] {
|
||||
if currPoint.H != nil {
|
||||
return nil // Range contains a mix of histograms and floats.
|
||||
}
|
||||
if !isCounter {
|
||||
continue
|
||||
}
|
||||
if currPoint.V < prevValue {
|
||||
resultValue += prevValue
|
||||
}
|
||||
prevValue = currPoint.V
|
||||
}
|
||||
lastValue = sample.V
|
||||
}
|
||||
resultValue := lastValue - samples.Points[0].V + counterCorrection
|
||||
|
||||
// Duration between first/last samples and boundary of range.
|
||||
durationToStart := float64(samples.Points[0].T-rangeStart) / 1000
|
||||
@@ -90,6 +116,7 @@ func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNod
|
||||
sampledInterval := float64(samples.Points[len(samples.Points)-1].T-samples.Points[0].T) / 1000
|
||||
averageDurationBetweenSamples := sampledInterval / float64(len(samples.Points)-1)
|
||||
|
||||
// TODO(beorn7): Do this for histograms, too.
|
||||
if isCounter && resultValue > 0 && samples.Points[0].V >= 0 {
|
||||
// Counters cannot be negative. If we have any slope at
|
||||
// all (i.e. resultValue went up), we can extrapolate
|
||||
@@ -121,16 +148,69 @@ func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNod
|
||||
} else {
|
||||
extrapolateToInterval += averageDurationBetweenSamples / 2
|
||||
}
|
||||
resultValue = resultValue * (extrapolateToInterval / sampledInterval)
|
||||
factor := extrapolateToInterval / sampledInterval
|
||||
if isRate {
|
||||
resultValue = resultValue / ms.Range.Seconds()
|
||||
factor /= ms.Range.Seconds()
|
||||
}
|
||||
if resultHistogram == nil {
|
||||
resultValue *= factor
|
||||
} else {
|
||||
resultHistogram.Scale(factor)
|
||||
}
|
||||
|
||||
return append(enh.Out, Sample{
|
||||
Point: Point{V: resultValue},
|
||||
Point: Point{V: resultValue, H: resultHistogram},
|
||||
})
|
||||
}
|
||||
|
||||
// histogramRate is a helper function for extrapolatedRate. It requires
|
||||
// points[0] to be a histogram. It returns nil if any other Point in points is
|
||||
// not a histogram.
|
||||
func histogramRate(points []Point, isCounter bool) *histogram.FloatHistogram {
|
||||
prev := points[0].H // We already know that this is a histogram.
|
||||
last := points[len(points)-1].H
|
||||
if last == nil {
|
||||
return nil // Range contains a mix of histograms and floats.
|
||||
}
|
||||
minSchema := prev.Schema
|
||||
if last.Schema < minSchema {
|
||||
minSchema = last.Schema
|
||||
}
|
||||
|
||||
// First iteration to find out two things:
|
||||
// - What's the smallest relevant schema?
|
||||
// - Are all data points histograms?
|
||||
// TODO(beorn7): Find a way to check that earlier, e.g. by handing in a
|
||||
// []FloatPoint and a []HistogramPoint separately.
|
||||
for _, currPoint := range points[1 : len(points)-1] {
|
||||
curr := currPoint.H
|
||||
if curr == nil {
|
||||
return nil // Range contains a mix of histograms and floats.
|
||||
}
|
||||
if !isCounter {
|
||||
continue
|
||||
}
|
||||
if curr.Schema < minSchema {
|
||||
minSchema = curr.Schema
|
||||
}
|
||||
}
|
||||
|
||||
h := last.CopyToSchema(minSchema)
|
||||
h.Sub(prev)
|
||||
|
||||
if isCounter {
|
||||
// Second iteration to deal with counter resets.
|
||||
for _, currPoint := range points[1:] {
|
||||
curr := currPoint.H
|
||||
if curr.DetectReset(prev) {
|
||||
h.Add(prev)
|
||||
}
|
||||
prev = curr
|
||||
}
|
||||
}
|
||||
return h.Compact(0)
|
||||
}
|
||||
|
||||
// === delta(Matrix parser.ValueTypeMatrix) Vector ===
|
||||
func funcDelta(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return extrapolatedRate(vals, args, enh, false, false)
|
||||
@@ -222,12 +302,12 @@ func funcHoltWinters(vals []parser.Value, args parser.Expressions, enh *EvalNode
|
||||
// The trend factor argument.
|
||||
tf := vals[2].(Vector)[0].V
|
||||
|
||||
// Sanity check the input.
|
||||
// Check that the input parameters are valid.
|
||||
if sf <= 0 || sf >= 1 {
|
||||
panic(errors.Errorf("invalid smoothing factor. Expected: 0 < sf < 1, got: %f", sf))
|
||||
panic(fmt.Errorf("invalid smoothing factor. Expected: 0 < sf < 1, got: %f", sf))
|
||||
}
|
||||
if tf <= 0 || tf >= 1 {
|
||||
panic(errors.Errorf("invalid trend factor. Expected: 0 < tf < 1, got: %f", tf))
|
||||
panic(fmt.Errorf("invalid trend factor. Expected: 0 < tf < 1, got: %f", tf))
|
||||
}
|
||||
|
||||
l := len(samples.Points)
|
||||
@@ -279,6 +359,23 @@ func funcSortDesc(vals []parser.Value, args parser.Expressions, enh *EvalNodeHel
|
||||
return Vector(byValueSorter)
|
||||
}
|
||||
|
||||
// === clamp(Vector parser.ValueTypeVector, min, max Scalar) Vector ===
|
||||
func funcClamp(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
vec := vals[0].(Vector)
|
||||
min := vals[1].(Vector)[0].Point.V
|
||||
max := vals[2].(Vector)[0].Point.V
|
||||
if max < min {
|
||||
return enh.Out
|
||||
}
|
||||
for _, el := range vec {
|
||||
enh.Out = append(enh.Out, Sample{
|
||||
Metric: enh.DropMetricName(el.Metric),
|
||||
Point: Point{V: math.Max(min, math.Min(max, el.V))},
|
||||
})
|
||||
}
|
||||
return enh.Out
|
||||
}
|
||||
|
||||
// === clamp_max(Vector parser.ValueTypeVector, max Scalar) Vector ===
|
||||
func funcClampMax(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
vec := vals[0].(Vector)
|
||||
@@ -351,7 +448,7 @@ func aggrOverTime(vals []parser.Value, enh *EvalNodeHelper, aggrFn func([]Point)
|
||||
// === avg_over_time(Matrix parser.ValueTypeMatrix) Vector ===
|
||||
func funcAvgOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return aggrOverTime(vals, enh, func(values []Point) float64 {
|
||||
var mean, count float64
|
||||
var mean, count, c float64
|
||||
for _, v := range values {
|
||||
count++
|
||||
if math.IsInf(mean, 0) {
|
||||
@@ -371,9 +468,13 @@ func funcAvgOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNode
|
||||
continue
|
||||
}
|
||||
}
|
||||
mean += v.V/count - mean/count
|
||||
mean, c = kahanSumInc(v.V/count-mean/count, mean, c)
|
||||
}
|
||||
return mean
|
||||
|
||||
if math.IsInf(mean, 0) {
|
||||
return mean
|
||||
}
|
||||
return mean + c
|
||||
})
|
||||
}
|
||||
|
||||
@@ -384,7 +485,16 @@ func funcCountOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNo
|
||||
})
|
||||
}
|
||||
|
||||
// === floor(Vector parser.ValueTypeVector) Vector ===
|
||||
// === last_over_time(Matrix parser.ValueTypeMatrix) Vector ===
|
||||
func funcLastOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
el := vals[0].(Matrix)[0]
|
||||
|
||||
return append(enh.Out, Sample{
|
||||
Metric: el.Metric,
|
||||
Point: Point{V: el.Points[len(el.Points)-1].V},
|
||||
})
|
||||
}
|
||||
|
||||
// === max_over_time(Matrix parser.ValueTypeMatrix) Vector ===
|
||||
func funcMaxOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return aggrOverTime(vals, enh, func(values []Point) float64 {
|
||||
@@ -414,11 +524,14 @@ func funcMinOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNode
|
||||
// === sum_over_time(Matrix parser.ValueTypeMatrix) Vector ===
|
||||
func funcSumOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return aggrOverTime(vals, enh, func(values []Point) float64 {
|
||||
var sum float64
|
||||
var sum, c float64
|
||||
for _, v := range values {
|
||||
sum += v.V
|
||||
sum, c = kahanSumInc(v.V, sum, c)
|
||||
}
|
||||
return sum
|
||||
if math.IsInf(sum, 0) {
|
||||
return sum
|
||||
}
|
||||
return sum + c
|
||||
})
|
||||
}
|
||||
|
||||
@@ -439,28 +552,32 @@ func funcQuantileOverTime(vals []parser.Value, args parser.Expressions, enh *Eva
|
||||
// === stddev_over_time(Matrix parser.ValueTypeMatrix) Vector ===
|
||||
func funcStddevOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return aggrOverTime(vals, enh, func(values []Point) float64 {
|
||||
var aux, count, mean float64
|
||||
var count float64
|
||||
var mean, cMean float64
|
||||
var aux, cAux float64
|
||||
for _, v := range values {
|
||||
count++
|
||||
delta := v.V - mean
|
||||
mean += delta / count
|
||||
aux += delta * (v.V - mean)
|
||||
delta := v.V - (mean + cMean)
|
||||
mean, cMean = kahanSumInc(delta/count, mean, cMean)
|
||||
aux, cAux = kahanSumInc(delta*(v.V-(mean+cMean)), aux, cAux)
|
||||
}
|
||||
return math.Sqrt(aux / count)
|
||||
return math.Sqrt((aux + cAux) / count)
|
||||
})
|
||||
}
|
||||
|
||||
// === stdvar_over_time(Matrix parser.ValueTypeMatrix) Vector ===
|
||||
func funcStdvarOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return aggrOverTime(vals, enh, func(values []Point) float64 {
|
||||
var aux, count, mean float64
|
||||
var count float64
|
||||
var mean, cMean float64
|
||||
var aux, cAux float64
|
||||
for _, v := range values {
|
||||
count++
|
||||
delta := v.V - mean
|
||||
mean += delta / count
|
||||
aux += delta * (v.V - mean)
|
||||
delta := v.V - (mean + cMean)
|
||||
mean, cMean = kahanSumInc(delta/count, mean, cMean)
|
||||
aux, cAux = kahanSumInc(delta*(v.V-(mean+cMean)), aux, cAux)
|
||||
}
|
||||
return aux / count
|
||||
return (aux + cAux) / count
|
||||
})
|
||||
}
|
||||
|
||||
@@ -488,6 +605,13 @@ func funcAbsentOverTime(vals []parser.Value, args parser.Expressions, enh *EvalN
|
||||
})
|
||||
}
|
||||
|
||||
// === present_over_time(Vector parser.ValueTypeMatrix) Vector ===
|
||||
func funcPresentOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return aggrOverTime(vals, enh, func(values []Point) float64 {
|
||||
return 1
|
||||
})
|
||||
}
|
||||
|
||||
func simpleFunc(vals []parser.Value, enh *EvalNodeHelper, f func(float64) float64) Vector {
|
||||
for _, el := range vals[0].(Vector) {
|
||||
enh.Out = append(enh.Out, Sample{
|
||||
@@ -538,6 +662,99 @@ func funcLog10(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper
|
||||
return simpleFunc(vals, enh, math.Log10)
|
||||
}
|
||||
|
||||
// === sin(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcSin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Sin)
|
||||
}
|
||||
|
||||
// === cos(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcCos(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Cos)
|
||||
}
|
||||
|
||||
// === tan(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcTan(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Tan)
|
||||
}
|
||||
|
||||
// == asin(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcAsin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Asin)
|
||||
}
|
||||
|
||||
// == acos(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcAcos(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Acos)
|
||||
}
|
||||
|
||||
// == atan(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcAtan(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Atan)
|
||||
}
|
||||
|
||||
// == sinh(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcSinh(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Sinh)
|
||||
}
|
||||
|
||||
// == cosh(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcCosh(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Cosh)
|
||||
}
|
||||
|
||||
// == tanh(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcTanh(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Tanh)
|
||||
}
|
||||
|
||||
// == asinh(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcAsinh(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Asinh)
|
||||
}
|
||||
|
||||
// == acosh(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcAcosh(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Acosh)
|
||||
}
|
||||
|
||||
// == atanh(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcAtanh(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, math.Atanh)
|
||||
}
|
||||
|
||||
// === rad(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcRad(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, func(v float64) float64 {
|
||||
return v * math.Pi / 180
|
||||
})
|
||||
}
|
||||
|
||||
// === deg(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcDeg(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, func(v float64) float64 {
|
||||
return v * 180 / math.Pi
|
||||
})
|
||||
}
|
||||
|
||||
// === pi() Scalar ===
|
||||
func funcPi(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return Vector{Sample{Point: Point{
|
||||
V: math.Pi,
|
||||
}}}
|
||||
}
|
||||
|
||||
// === sgn(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcSgn(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return simpleFunc(vals, enh, func(v float64) float64 {
|
||||
if v < 0 {
|
||||
return -1
|
||||
} else if v > 0 {
|
||||
return 1
|
||||
}
|
||||
return v
|
||||
})
|
||||
}
|
||||
|
||||
// === timestamp(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcTimestamp(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
vec := vals[0].(Vector)
|
||||
@@ -550,23 +767,64 @@ func funcTimestamp(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
|
||||
return enh.Out
|
||||
}
|
||||
|
||||
func kahanSum(samples []float64) float64 {
|
||||
var sum, c float64
|
||||
|
||||
for _, v := range samples {
|
||||
sum, c = kahanSumInc(v, sum, c)
|
||||
}
|
||||
return sum + c
|
||||
}
|
||||
|
||||
func kahanSumInc(inc, sum, c float64) (newSum, newC float64) {
|
||||
t := sum + inc
|
||||
// Using Neumaier improvement, swap if next term larger than sum.
|
||||
if math.Abs(sum) >= math.Abs(inc) {
|
||||
c += (sum - t) + inc
|
||||
} else {
|
||||
c += (inc - t) + sum
|
||||
}
|
||||
return t, c
|
||||
}
|
||||
|
||||
// linearRegression performs a least-square linear regression analysis on the
|
||||
// provided SamplePairs. It returns the slope, and the intercept value at the
|
||||
// provided time.
|
||||
func linearRegression(samples []Point, interceptTime int64) (slope, intercept float64) {
|
||||
var (
|
||||
n float64
|
||||
sumX, sumY float64
|
||||
sumXY, sumX2 float64
|
||||
n float64
|
||||
sumX, cX float64
|
||||
sumY, cY float64
|
||||
sumXY, cXY float64
|
||||
sumX2, cX2 float64
|
||||
initY float64
|
||||
constY bool
|
||||
)
|
||||
for _, sample := range samples {
|
||||
x := float64(sample.T-interceptTime) / 1e3
|
||||
initY = samples[0].V
|
||||
constY = true
|
||||
for i, sample := range samples {
|
||||
// Set constY to false if any new y values are encountered.
|
||||
if constY && i > 0 && sample.V != initY {
|
||||
constY = false
|
||||
}
|
||||
n += 1.0
|
||||
sumY += sample.V
|
||||
sumX += x
|
||||
sumXY += x * sample.V
|
||||
sumX2 += x * x
|
||||
x := float64(sample.T-interceptTime) / 1e3
|
||||
sumX, cX = kahanSumInc(x, sumX, cX)
|
||||
sumY, cY = kahanSumInc(sample.V, sumY, cY)
|
||||
sumXY, cXY = kahanSumInc(x*sample.V, sumXY, cXY)
|
||||
sumX2, cX2 = kahanSumInc(x*x, sumX2, cX2)
|
||||
}
|
||||
if constY {
|
||||
if math.IsInf(initY, 0) {
|
||||
return math.NaN(), math.NaN()
|
||||
}
|
||||
return 0, initY
|
||||
}
|
||||
sumX = sumX + cX
|
||||
sumY = sumY + cY
|
||||
sumXY = sumXY + cXY
|
||||
sumX2 = sumX2 + cX2
|
||||
|
||||
covXY := sumXY - sumX*sumY/n
|
||||
varX := sumX2 - sumX*sumX/n
|
||||
|
||||
@@ -598,7 +856,6 @@ func funcDeriv(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper
|
||||
func funcPredictLinear(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
samples := vals[0].(Matrix)[0]
|
||||
duration := vals[1].(Vector)[0].V
|
||||
|
||||
// No sense in trying to predict anything without at least two points.
|
||||
// Drop this Vector element.
|
||||
if len(samples.Points) < 2 {
|
||||
@@ -611,11 +868,63 @@ func funcPredictLinear(vals []parser.Value, args parser.Expressions, enh *EvalNo
|
||||
})
|
||||
}
|
||||
|
||||
// === histogram_count(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcHistogramCount(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
inVec := vals[0].(Vector)
|
||||
|
||||
for _, sample := range inVec {
|
||||
// Skip non-histogram samples.
|
||||
if sample.H == nil {
|
||||
continue
|
||||
}
|
||||
enh.Out = append(enh.Out, Sample{
|
||||
Metric: enh.DropMetricName(sample.Metric),
|
||||
Point: Point{V: sample.H.Count},
|
||||
})
|
||||
}
|
||||
return enh.Out
|
||||
}
|
||||
|
||||
// === histogram_sum(Vector parser.ValueTypeVector) Vector ===
|
||||
func funcHistogramSum(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
inVec := vals[0].(Vector)
|
||||
|
||||
for _, sample := range inVec {
|
||||
// Skip non-histogram samples.
|
||||
if sample.H == nil {
|
||||
continue
|
||||
}
|
||||
enh.Out = append(enh.Out, Sample{
|
||||
Metric: enh.DropMetricName(sample.Metric),
|
||||
Point: Point{V: sample.H.Sum},
|
||||
})
|
||||
}
|
||||
return enh.Out
|
||||
}
|
||||
|
||||
// === histogram_fraction(lower, upper parser.ValueTypeScalar, Vector parser.ValueTypeVector) Vector ===
|
||||
func funcHistogramFraction(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
lower := vals[0].(Vector)[0].V
|
||||
upper := vals[1].(Vector)[0].V
|
||||
inVec := vals[2].(Vector)
|
||||
|
||||
for _, sample := range inVec {
|
||||
// Skip non-histogram samples.
|
||||
if sample.H == nil {
|
||||
continue
|
||||
}
|
||||
enh.Out = append(enh.Out, Sample{
|
||||
Metric: enh.DropMetricName(sample.Metric),
|
||||
Point: Point{V: histogramFraction(lower, upper, sample.H)},
|
||||
})
|
||||
}
|
||||
return enh.Out
|
||||
}
|
||||
|
||||
// === histogram_quantile(k parser.ValueTypeScalar, Vector parser.ValueTypeVector) Vector ===
|
||||
func funcHistogramQuantile(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
q := vals[0].(Vector)[0].V
|
||||
inVec := vals[1].(Vector)
|
||||
sigf := signatureFunc(false, enh.lblBuf, excludedLabels...)
|
||||
|
||||
if enh.signatureToMetricWithBuckets == nil {
|
||||
enh.signatureToMetricWithBuckets = map[string]*metricWithBuckets{}
|
||||
@@ -624,27 +933,57 @@ func funcHistogramQuantile(vals []parser.Value, args parser.Expressions, enh *Ev
|
||||
v.buckets = v.buckets[:0]
|
||||
}
|
||||
}
|
||||
for _, el := range inVec {
|
||||
|
||||
var histogramSamples []Sample
|
||||
|
||||
for _, sample := range inVec {
|
||||
// We are only looking for conventional buckets here. Remember
|
||||
// the histograms for later treatment.
|
||||
if sample.H != nil {
|
||||
histogramSamples = append(histogramSamples, sample)
|
||||
continue
|
||||
}
|
||||
|
||||
upperBound, err := strconv.ParseFloat(
|
||||
el.Metric.Get(model.BucketLabel), 64,
|
||||
sample.Metric.Get(model.BucketLabel), 64,
|
||||
)
|
||||
if err != nil {
|
||||
// Oops, no bucket label or malformed label value. Skip.
|
||||
// TODO(beorn7): Issue a warning somehow.
|
||||
continue
|
||||
}
|
||||
l := sigf(el.Metric)
|
||||
|
||||
mb, ok := enh.signatureToMetricWithBuckets[l]
|
||||
enh.lblBuf = sample.Metric.BytesWithoutLabels(enh.lblBuf, labels.BucketLabel)
|
||||
mb, ok := enh.signatureToMetricWithBuckets[string(enh.lblBuf)]
|
||||
if !ok {
|
||||
el.Metric = labels.NewBuilder(el.Metric).
|
||||
Del(labels.BucketLabel, labels.MetricName).
|
||||
Labels()
|
||||
sample.Metric = labels.NewBuilder(sample.Metric).
|
||||
Del(excludedLabels...).
|
||||
Labels(labels.EmptyLabels())
|
||||
|
||||
mb = &metricWithBuckets{el.Metric, nil}
|
||||
enh.signatureToMetricWithBuckets[l] = mb
|
||||
mb = &metricWithBuckets{sample.Metric, nil}
|
||||
enh.signatureToMetricWithBuckets[string(enh.lblBuf)] = mb
|
||||
}
|
||||
mb.buckets = append(mb.buckets, bucket{upperBound, el.V})
|
||||
mb.buckets = append(mb.buckets, bucket{upperBound, sample.V})
|
||||
|
||||
}
|
||||
|
||||
// Now deal with the histograms.
|
||||
for _, sample := range histogramSamples {
|
||||
// We have to reconstruct the exact same signature as above for
|
||||
// a conventional histogram, just ignoring any le label.
|
||||
enh.lblBuf = sample.Metric.Bytes(enh.lblBuf)
|
||||
if mb, ok := enh.signatureToMetricWithBuckets[string(enh.lblBuf)]; ok && len(mb.buckets) > 0 {
|
||||
// At this data point, we have conventional histogram
|
||||
// buckets and a native histogram with the same name and
|
||||
// labels. Do not evaluate anything.
|
||||
// TODO(beorn7): Issue a warning somehow.
|
||||
delete(enh.signatureToMetricWithBuckets, string(enh.lblBuf))
|
||||
continue
|
||||
}
|
||||
|
||||
enh.Out = append(enh.Out, Sample{
|
||||
Metric: enh.DropMetricName(sample.Metric),
|
||||
Point: Point{V: histogramQuantile(q, sample.H)},
|
||||
})
|
||||
}
|
||||
|
||||
for _, mb := range enh.signatureToMetricWithBuckets {
|
||||
@@ -701,20 +1040,20 @@ func funcChanges(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelp
|
||||
func funcLabelReplace(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
var (
|
||||
vector = vals[0].(Vector)
|
||||
dst = args[1].(*parser.StringLiteral).Val
|
||||
repl = args[2].(*parser.StringLiteral).Val
|
||||
src = args[3].(*parser.StringLiteral).Val
|
||||
regexStr = args[4].(*parser.StringLiteral).Val
|
||||
dst = stringFromArg(args[1])
|
||||
repl = stringFromArg(args[2])
|
||||
src = stringFromArg(args[3])
|
||||
regexStr = stringFromArg(args[4])
|
||||
)
|
||||
|
||||
if enh.regex == nil {
|
||||
var err error
|
||||
enh.regex, err = regexp.Compile("^(?:" + regexStr + ")$")
|
||||
if err != nil {
|
||||
panic(errors.Errorf("invalid regular expression in label_replace(): %s", regexStr))
|
||||
panic(fmt.Errorf("invalid regular expression in label_replace(): %s", regexStr))
|
||||
}
|
||||
if !model.LabelNameRE.MatchString(dst) {
|
||||
panic(errors.Errorf("invalid destination label name in label_replace(): %s", dst))
|
||||
panic(fmt.Errorf("invalid destination label name in label_replace(): %s", dst))
|
||||
}
|
||||
enh.Dmn = make(map[uint64]labels.Labels, len(enh.Out))
|
||||
}
|
||||
@@ -738,7 +1077,7 @@ func funcLabelReplace(vals []parser.Value, args parser.Expressions, enh *EvalNod
|
||||
if len(res) > 0 {
|
||||
lb.Set(dst, string(res))
|
||||
}
|
||||
outMetric = lb.Labels()
|
||||
outMetric = lb.Labels(labels.EmptyLabels())
|
||||
enh.Dmn[h] = outMetric
|
||||
}
|
||||
}
|
||||
@@ -764,8 +1103,8 @@ func funcVector(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelpe
|
||||
func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
var (
|
||||
vector = vals[0].(Vector)
|
||||
dst = args[1].(*parser.StringLiteral).Val
|
||||
sep = args[2].(*parser.StringLiteral).Val
|
||||
dst = stringFromArg(args[1])
|
||||
sep = stringFromArg(args[2])
|
||||
srcLabels = make([]string, len(args)-3)
|
||||
)
|
||||
|
||||
@@ -774,15 +1113,15 @@ func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
|
||||
}
|
||||
|
||||
for i := 3; i < len(args); i++ {
|
||||
src := args[i].(*parser.StringLiteral).Val
|
||||
src := stringFromArg(args[i])
|
||||
if !model.LabelName(src).IsValid() {
|
||||
panic(errors.Errorf("invalid source label name in label_join(): %s", src))
|
||||
panic(fmt.Errorf("invalid source label name in label_join(): %s", src))
|
||||
}
|
||||
srcLabels[i-3] = src
|
||||
}
|
||||
|
||||
if !model.LabelName(dst).IsValid() {
|
||||
panic(errors.Errorf("invalid destination label name in label_join(): %s", dst))
|
||||
panic(fmt.Errorf("invalid destination label name in label_join(): %s", dst))
|
||||
}
|
||||
|
||||
srcVals := make([]string, len(srcLabels))
|
||||
@@ -806,7 +1145,7 @@ func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
|
||||
lb.Set(dst, strval)
|
||||
}
|
||||
|
||||
outMetric = lb.Labels()
|
||||
outMetric = lb.Labels(labels.EmptyLabels())
|
||||
enh.Dmn[h] = outMetric
|
||||
}
|
||||
|
||||
@@ -859,6 +1198,13 @@ func funcDayOfWeek(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
|
||||
})
|
||||
}
|
||||
|
||||
// === day_of_year(v Vector) Scalar ===
|
||||
func funcDayOfYear(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return dateWrapper(vals, enh, func(t time.Time) float64 {
|
||||
return float64(t.YearDay())
|
||||
})
|
||||
}
|
||||
|
||||
// === hour(v Vector) Scalar ===
|
||||
func funcHour(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
|
||||
return dateWrapper(vals, enh, func(t time.Time) float64 {
|
||||
@@ -892,20 +1238,34 @@ var FunctionCalls = map[string]FunctionCall{
|
||||
"abs": funcAbs,
|
||||
"absent": funcAbsent,
|
||||
"absent_over_time": funcAbsentOverTime,
|
||||
"acos": funcAcos,
|
||||
"acosh": funcAcosh,
|
||||
"asin": funcAsin,
|
||||
"asinh": funcAsinh,
|
||||
"atan": funcAtan,
|
||||
"atanh": funcAtanh,
|
||||
"avg_over_time": funcAvgOverTime,
|
||||
"ceil": funcCeil,
|
||||
"changes": funcChanges,
|
||||
"clamp": funcClamp,
|
||||
"clamp_max": funcClampMax,
|
||||
"clamp_min": funcClampMin,
|
||||
"cos": funcCos,
|
||||
"cosh": funcCosh,
|
||||
"count_over_time": funcCountOverTime,
|
||||
"days_in_month": funcDaysInMonth,
|
||||
"day_of_month": funcDayOfMonth,
|
||||
"day_of_week": funcDayOfWeek,
|
||||
"day_of_year": funcDayOfYear,
|
||||
"deg": funcDeg,
|
||||
"delta": funcDelta,
|
||||
"deriv": funcDeriv,
|
||||
"exp": funcExp,
|
||||
"floor": funcFloor,
|
||||
"histogram_count": funcHistogramCount,
|
||||
"histogram_fraction": funcHistogramFraction,
|
||||
"histogram_quantile": funcHistogramQuantile,
|
||||
"histogram_sum": funcHistogramSum,
|
||||
"holt_winters": funcHoltWinters,
|
||||
"hour": funcHour,
|
||||
"idelta": funcIdelta,
|
||||
@@ -916,28 +1276,52 @@ var FunctionCalls = map[string]FunctionCall{
|
||||
"ln": funcLn,
|
||||
"log10": funcLog10,
|
||||
"log2": funcLog2,
|
||||
"last_over_time": funcLastOverTime,
|
||||
"max_over_time": funcMaxOverTime,
|
||||
"min_over_time": funcMinOverTime,
|
||||
"minute": funcMinute,
|
||||
"month": funcMonth,
|
||||
"pi": funcPi,
|
||||
"predict_linear": funcPredictLinear,
|
||||
"present_over_time": funcPresentOverTime,
|
||||
"quantile_over_time": funcQuantileOverTime,
|
||||
"rad": funcRad,
|
||||
"rate": funcRate,
|
||||
"resets": funcResets,
|
||||
"round": funcRound,
|
||||
"scalar": funcScalar,
|
||||
"sgn": funcSgn,
|
||||
"sin": funcSin,
|
||||
"sinh": funcSinh,
|
||||
"sort": funcSort,
|
||||
"sort_desc": funcSortDesc,
|
||||
"sqrt": funcSqrt,
|
||||
"stddev_over_time": funcStddevOverTime,
|
||||
"stdvar_over_time": funcStdvarOverTime,
|
||||
"sum_over_time": funcSumOverTime,
|
||||
"tan": funcTan,
|
||||
"tanh": funcTanh,
|
||||
"time": funcTime,
|
||||
"timestamp": funcTimestamp,
|
||||
"vector": funcVector,
|
||||
"year": funcYear,
|
||||
}
|
||||
|
||||
// AtModifierUnsafeFunctions are the functions whose result
|
||||
// can vary if evaluation time is changed when the arguments are
|
||||
// step invariant. It also includes functions that use the timestamps
|
||||
// of the passed instant vector argument to calculate a result since
|
||||
// that can also change with change in eval time.
|
||||
var AtModifierUnsafeFunctions = map[string]struct{}{
|
||||
// Step invariant functions.
|
||||
"days_in_month": {}, "day_of_month": {}, "day_of_week": {}, "day_of_year": {},
|
||||
"hour": {}, "minute": {}, "month": {}, "year": {},
|
||||
"predict_linear": {}, "time": {},
|
||||
// Uses timestamp of the argument for the result,
|
||||
// hence unsafe to use with @ modifier.
|
||||
"timestamp": {},
|
||||
}
|
||||
|
||||
type vectorByValueHeap Vector
|
||||
|
||||
func (s vectorByValueHeap) Len() int {
|
||||
@@ -999,7 +1383,7 @@ func (s *vectorByReverseValueHeap) Pop() interface{} {
|
||||
// createLabelsForAbsentFunction returns the labels that are uniquely and exactly matched
|
||||
// in a given expression. It is used in the absent functions.
|
||||
func createLabelsForAbsentFunction(expr parser.Expr) labels.Labels {
|
||||
m := labels.Labels{}
|
||||
b := labels.NewBuilder(labels.EmptyLabels())
|
||||
|
||||
var lm []*labels.Matcher
|
||||
switch n := expr.(type) {
|
||||
@@ -1008,23 +1392,30 @@ func createLabelsForAbsentFunction(expr parser.Expr) labels.Labels {
|
||||
case *parser.MatrixSelector:
|
||||
lm = n.VectorSelector.(*parser.VectorSelector).LabelMatchers
|
||||
default:
|
||||
return m
|
||||
return labels.EmptyLabels()
|
||||
}
|
||||
|
||||
empty := []string{}
|
||||
// The 'has' map implements backwards-compatibility for historic behaviour:
|
||||
// e.g. in `absent(x{job="a",job="b",foo="bar"})` then `job` is removed from the output.
|
||||
// Note this gives arguably wrong behaviour for `absent(x{job="a",job="a",foo="bar"})`.
|
||||
has := make(map[string]bool, len(lm))
|
||||
for _, ma := range lm {
|
||||
if ma.Name == labels.MetricName {
|
||||
continue
|
||||
}
|
||||
if ma.Type == labels.MatchEqual && !m.Has(ma.Name) {
|
||||
m = labels.NewBuilder(m).Set(ma.Name, ma.Value).Labels()
|
||||
if ma.Type == labels.MatchEqual && !has[ma.Name] {
|
||||
b.Set(ma.Name, ma.Value)
|
||||
has[ma.Name] = true
|
||||
} else {
|
||||
empty = append(empty, ma.Name)
|
||||
b.Del(ma.Name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range empty {
|
||||
m = labels.NewBuilder(m).Del(v).Labels()
|
||||
}
|
||||
return m
|
||||
return b.Labels(labels.EmptyLabels())
|
||||
}
|
||||
|
||||
func stringFromArg(e parser.Expr) string {
|
||||
tmp := unwrapStepInvariantExpr(e) // Unwrap StepInvariant
|
||||
unwrapParenExpr(&tmp) // Optionally unwrap ParenExpr
|
||||
return tmp.(*parser.StringLiteral).Val
|
||||
}
|
||||
|
||||
14
vendor/github.com/prometheus/prometheus/promql/fuzz.go
generated
vendored
14
vendor/github.com/prometheus/prometheus/promql/fuzz.go
generated
vendored
@@ -12,14 +12,16 @@
|
||||
// limitations under the License.
|
||||
|
||||
// Only build when go-fuzz is in use
|
||||
//go:build gofuzz
|
||||
// +build gofuzz
|
||||
|
||||
package promql
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/prometheus/prometheus/pkg/textparse"
|
||||
"github.com/prometheus/prometheus/model/textparse"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
)
|
||||
|
||||
@@ -56,7 +58,13 @@ const (
|
||||
)
|
||||
|
||||
func fuzzParseMetricWithContentType(in []byte, contentType string) int {
|
||||
p := textparse.New(in, contentType)
|
||||
p, warning := textparse.New(in, contentType)
|
||||
if warning != nil {
|
||||
// An invalid content type is being passed, which should not happen
|
||||
// in this context.
|
||||
panic(warning)
|
||||
}
|
||||
|
||||
var err error
|
||||
for {
|
||||
_, err = p.Next()
|
||||
@@ -64,7 +72,7 @@ func fuzzParseMetricWithContentType(in []byte, contentType string) int {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
if errors.Is(err, io.EOF) {
|
||||
err = nil
|
||||
}
|
||||
|
||||
|
||||
118
vendor/github.com/prometheus/prometheus/promql/parser/ast.go
generated
vendored
118
vendor/github.com/prometheus/prometheus/promql/parser/ast.go
generated
vendored
@@ -15,11 +15,10 @@ package parser
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/prometheus/prometheus/pkg/labels"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/storage"
|
||||
)
|
||||
|
||||
@@ -29,18 +28,22 @@ import (
|
||||
// or a chain of function definitions (e.g. String(), PromQLExpr(), etc.) convention is
|
||||
// to list them as follows:
|
||||
//
|
||||
// - Statements
|
||||
// - statement types (alphabetical)
|
||||
// - ...
|
||||
// - Expressions
|
||||
// - expression types (alphabetical)
|
||||
// - ...
|
||||
//
|
||||
// - Statements
|
||||
// - statement types (alphabetical)
|
||||
// - ...
|
||||
// - Expressions
|
||||
// - expression types (alphabetical)
|
||||
// - ...
|
||||
type Node interface {
|
||||
// String representation of the node that returns the given node when parsed
|
||||
// as part of a valid query.
|
||||
String() string
|
||||
|
||||
// Pretty returns the prettified representation of the node.
|
||||
// It uses the level information to determine at which level/depth the current
|
||||
// node is in the AST and uses this to apply indentation.
|
||||
Pretty(level int) string
|
||||
|
||||
// PositionRange returns the position of the AST Node in the query string.
|
||||
PositionRange() PositionRange
|
||||
}
|
||||
@@ -64,6 +67,8 @@ type EvalStmt struct {
|
||||
Start, End time.Time
|
||||
// Time between two evaluated instants for the range [Start:End].
|
||||
Interval time.Duration
|
||||
// Lookback delta to use for this evaluation.
|
||||
LookbackDelta time.Duration
|
||||
}
|
||||
|
||||
func (*EvalStmt) PromQLStmt() {}
|
||||
@@ -125,10 +130,18 @@ type MatrixSelector struct {
|
||||
|
||||
// SubqueryExpr represents a subquery.
|
||||
type SubqueryExpr struct {
|
||||
Expr Expr
|
||||
Range time.Duration
|
||||
Offset time.Duration
|
||||
Step time.Duration
|
||||
Expr Expr
|
||||
Range time.Duration
|
||||
// OriginalOffset is the actual offset that was set in the query.
|
||||
// This never changes.
|
||||
OriginalOffset time.Duration
|
||||
// Offset is the offset used during the query execution
|
||||
// which is calculated using the original offset, at modifier time,
|
||||
// eval time, and subquery offsets in the AST tree.
|
||||
Offset time.Duration
|
||||
Timestamp *int64
|
||||
StartOrEnd ItemType // Set when @ is used with start() or end()
|
||||
Step time.Duration
|
||||
|
||||
EndPos Pos
|
||||
}
|
||||
@@ -162,10 +175,29 @@ type UnaryExpr struct {
|
||||
StartPos Pos
|
||||
}
|
||||
|
||||
// StepInvariantExpr represents a query which evaluates to the same result
|
||||
// irrespective of the evaluation time given the raw samples from TSDB remain unchanged.
|
||||
// Currently this is only used for engine optimisations and the parser does not produce this.
|
||||
type StepInvariantExpr struct {
|
||||
Expr Expr
|
||||
}
|
||||
|
||||
func (e *StepInvariantExpr) String() string { return e.Expr.String() }
|
||||
|
||||
func (e *StepInvariantExpr) PositionRange() PositionRange { return e.Expr.PositionRange() }
|
||||
|
||||
// VectorSelector represents a Vector selection.
|
||||
type VectorSelector struct {
|
||||
Name string
|
||||
Name string
|
||||
// OriginalOffset is the actual offset that was set in the query.
|
||||
// This never changes.
|
||||
OriginalOffset time.Duration
|
||||
// Offset is the offset used during the query execution
|
||||
// which is calculated using the original offset, at modifier time,
|
||||
// eval time, and subquery offsets in the AST tree.
|
||||
Offset time.Duration
|
||||
Timestamp *int64
|
||||
StartOrEnd ItemType // Set when @ is used with start() or end()
|
||||
LabelMatchers []*labels.Matcher
|
||||
|
||||
// The unexpanded seriesSet populated at query preparation time.
|
||||
@@ -179,8 +211,9 @@ type VectorSelector struct {
|
||||
// of an arbitrary function during handling. It is used to test the Engine.
|
||||
type TestStmt func(context.Context) error
|
||||
|
||||
func (TestStmt) String() string { return "test statement" }
|
||||
func (TestStmt) PromQLStmt() {}
|
||||
func (TestStmt) String() string { return "test statement" }
|
||||
func (TestStmt) PromQLStmt() {}
|
||||
func (t TestStmt) Pretty(int) string { return t.String() }
|
||||
|
||||
func (TestStmt) PositionRange() PositionRange {
|
||||
return PositionRange{
|
||||
@@ -203,17 +236,19 @@ func (e *BinaryExpr) Type() ValueType {
|
||||
}
|
||||
return ValueTypeVector
|
||||
}
|
||||
func (e *StepInvariantExpr) Type() ValueType { return e.Expr.Type() }
|
||||
|
||||
func (*AggregateExpr) PromQLExpr() {}
|
||||
func (*BinaryExpr) PromQLExpr() {}
|
||||
func (*Call) PromQLExpr() {}
|
||||
func (*MatrixSelector) PromQLExpr() {}
|
||||
func (*SubqueryExpr) PromQLExpr() {}
|
||||
func (*NumberLiteral) PromQLExpr() {}
|
||||
func (*ParenExpr) PromQLExpr() {}
|
||||
func (*StringLiteral) PromQLExpr() {}
|
||||
func (*UnaryExpr) PromQLExpr() {}
|
||||
func (*VectorSelector) PromQLExpr() {}
|
||||
func (*AggregateExpr) PromQLExpr() {}
|
||||
func (*BinaryExpr) PromQLExpr() {}
|
||||
func (*Call) PromQLExpr() {}
|
||||
func (*MatrixSelector) PromQLExpr() {}
|
||||
func (*SubqueryExpr) PromQLExpr() {}
|
||||
func (*NumberLiteral) PromQLExpr() {}
|
||||
func (*ParenExpr) PromQLExpr() {}
|
||||
func (*StringLiteral) PromQLExpr() {}
|
||||
func (*UnaryExpr) PromQLExpr() {}
|
||||
func (*VectorSelector) PromQLExpr() {}
|
||||
func (*StepInvariantExpr) PromQLExpr() {}
|
||||
|
||||
// VectorMatchCardinality describes the cardinality relationship
|
||||
// of two Vectors in a binary operation.
|
||||
@@ -287,6 +322,18 @@ func Walk(v Visitor, node Node, path []Node) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func ExtractSelectors(expr Expr) [][]*labels.Matcher {
|
||||
var selectors [][]*labels.Matcher
|
||||
Inspect(expr, func(node Node, _ []Node) error {
|
||||
vs, ok := node.(*VectorSelector)
|
||||
if ok {
|
||||
selectors = append(selectors, vs.LabelMatchers)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return selectors
|
||||
}
|
||||
|
||||
type inspector func(Node, []Node) error
|
||||
|
||||
func (f inspector) Visit(node Node, path []Node) (Visitor, error) {
|
||||
@@ -347,11 +394,13 @@ func Children(node Node) []Node {
|
||||
return []Node{n.Expr}
|
||||
case *MatrixSelector:
|
||||
return []Node{n.VectorSelector}
|
||||
case *StepInvariantExpr:
|
||||
return []Node{n.Expr}
|
||||
case *NumberLiteral, *StringLiteral, *VectorSelector:
|
||||
// nothing to do
|
||||
return []Node{}
|
||||
default:
|
||||
panic(errors.Errorf("promql.Children: unhandled node type %T", node))
|
||||
panic(fmt.Errorf("promql.Children: unhandled node type %T", node))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +413,7 @@ type PositionRange struct {
|
||||
// mergeRanges is a helper function to merge the PositionRanges of two Nodes.
|
||||
// Note that the arguments must be in the same order as they
|
||||
// occur in the input string.
|
||||
func mergeRanges(first Node, last Node) PositionRange {
|
||||
func mergeRanges(first, last Node) PositionRange {
|
||||
return PositionRange{
|
||||
Start: first.PositionRange().Start,
|
||||
End: last.PositionRange().End,
|
||||
@@ -383,15 +432,19 @@ func (i *Item) PositionRange() PositionRange {
|
||||
func (e *AggregateExpr) PositionRange() PositionRange {
|
||||
return e.PosRange
|
||||
}
|
||||
|
||||
func (e *BinaryExpr) PositionRange() PositionRange {
|
||||
return mergeRanges(e.LHS, e.RHS)
|
||||
}
|
||||
|
||||
func (e *Call) PositionRange() PositionRange {
|
||||
return e.PosRange
|
||||
}
|
||||
|
||||
func (e *EvalStmt) PositionRange() PositionRange {
|
||||
return e.Expr.PositionRange()
|
||||
}
|
||||
|
||||
func (e Expressions) PositionRange() PositionRange {
|
||||
if len(e) == 0 {
|
||||
// Position undefined.
|
||||
@@ -402,33 +455,40 @@ func (e Expressions) PositionRange() PositionRange {
|
||||
}
|
||||
return mergeRanges(e[0], e[len(e)-1])
|
||||
}
|
||||
|
||||
func (e *MatrixSelector) PositionRange() PositionRange {
|
||||
return PositionRange{
|
||||
Start: e.VectorSelector.PositionRange().Start,
|
||||
End: e.EndPos,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *SubqueryExpr) PositionRange() PositionRange {
|
||||
return PositionRange{
|
||||
Start: e.Expr.PositionRange().Start,
|
||||
End: e.EndPos,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *NumberLiteral) PositionRange() PositionRange {
|
||||
return e.PosRange
|
||||
}
|
||||
|
||||
func (e *ParenExpr) PositionRange() PositionRange {
|
||||
return e.PosRange
|
||||
}
|
||||
|
||||
func (e *StringLiteral) PositionRange() PositionRange {
|
||||
return e.PosRange
|
||||
}
|
||||
|
||||
func (e *UnaryExpr) PositionRange() PositionRange {
|
||||
return PositionRange{
|
||||
Start: e.StartPos,
|
||||
End: e.Expr.PositionRange().End,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *VectorSelector) PositionRange() PositionRange {
|
||||
return e.PosRange
|
||||
}
|
||||
|
||||
116
vendor/github.com/prometheus/prometheus/promql/parser/functions.go
generated
vendored
116
vendor/github.com/prometheus/prometheus/promql/parser/functions.go
generated
vendored
@@ -39,6 +39,36 @@ var Functions = map[string]*Function{
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"acos": {
|
||||
Name: "acos",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"acosh": {
|
||||
Name: "acosh",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"asin": {
|
||||
Name: "asin",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"asinh": {
|
||||
Name: "asinh",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"atan": {
|
||||
Name: "atan",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"atanh": {
|
||||
Name: "atanh",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"avg_over_time": {
|
||||
Name: "avg_over_time",
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
@@ -54,6 +84,11 @@ var Functions = map[string]*Function{
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"clamp": {
|
||||
Name: "clamp",
|
||||
ArgTypes: []ValueType{ValueTypeVector, ValueTypeScalar, ValueTypeScalar},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"clamp_max": {
|
||||
Name: "clamp_max",
|
||||
ArgTypes: []ValueType{ValueTypeVector, ValueTypeScalar},
|
||||
@@ -64,6 +99,16 @@ var Functions = map[string]*Function{
|
||||
ArgTypes: []ValueType{ValueTypeVector, ValueTypeScalar},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"cos": {
|
||||
Name: "cos",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"cosh": {
|
||||
Name: "cosh",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"count_over_time": {
|
||||
Name: "count_over_time",
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
@@ -87,6 +132,17 @@ var Functions = map[string]*Function{
|
||||
Variadic: 1,
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"day_of_year": {
|
||||
Name: "day_of_year",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
Variadic: 1,
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"deg": {
|
||||
Name: "deg",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"delta": {
|
||||
Name: "delta",
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
@@ -107,6 +163,21 @@ var Functions = map[string]*Function{
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"histogram_count": {
|
||||
Name: "histogram_count",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"histogram_sum": {
|
||||
Name: "histogram_sum",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"histogram_fraction": {
|
||||
Name: "histogram_fraction",
|
||||
ArgTypes: []ValueType{ValueTypeScalar, ValueTypeScalar, ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"histogram_quantile": {
|
||||
Name: "histogram_quantile",
|
||||
ArgTypes: []ValueType{ValueTypeScalar, ValueTypeVector},
|
||||
@@ -149,6 +220,11 @@ var Functions = map[string]*Function{
|
||||
Variadic: -1,
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"last_over_time": {
|
||||
Name: "last_over_time",
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"ln": {
|
||||
Name: "ln",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
@@ -186,16 +262,31 @@ var Functions = map[string]*Function{
|
||||
Variadic: 1,
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"pi": {
|
||||
Name: "pi",
|
||||
ArgTypes: []ValueType{},
|
||||
ReturnType: ValueTypeScalar,
|
||||
},
|
||||
"predict_linear": {
|
||||
Name: "predict_linear",
|
||||
ArgTypes: []ValueType{ValueTypeMatrix, ValueTypeScalar},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"present_over_time": {
|
||||
Name: "present_over_time",
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"quantile_over_time": {
|
||||
Name: "quantile_over_time",
|
||||
ArgTypes: []ValueType{ValueTypeScalar, ValueTypeMatrix},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"rad": {
|
||||
Name: "rad",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"rate": {
|
||||
Name: "rate",
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
@@ -217,6 +308,21 @@ var Functions = map[string]*Function{
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeScalar,
|
||||
},
|
||||
"sgn": {
|
||||
Name: "sgn",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"sin": {
|
||||
Name: "sin",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"sinh": {
|
||||
Name: "sinh",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"sort": {
|
||||
Name: "sort",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
@@ -247,6 +353,16 @@ var Functions = map[string]*Function{
|
||||
ArgTypes: []ValueType{ValueTypeMatrix},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"tan": {
|
||||
Name: "tan",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"tanh": {
|
||||
Name: "tanh",
|
||||
ArgTypes: []ValueType{ValueTypeVector},
|
||||
ReturnType: ValueTypeVector,
|
||||
},
|
||||
"time": {
|
||||
Name: "time",
|
||||
ArgTypes: []ValueType{},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user