mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-23 20:37:12 +01:00
app/vmalert: expose /vmalert/api/v1/rule
and /api/v1/rule
API which returns rule status in JSON format (#5397)
* app/vmalert: expose `/vmalert/api/v1/rule` and `/api/v1/rule` API which returns rule status in JSON format * app/vmalert: hide updates if query param not set * app/vmalert: fix panic (recursion call) * app/vmalert: add needed group name and file name * app/vmalert: fix comment, update behavior * app/vmalert: fix description * app/vmalert: simplify API for /api/v1/rule Signed-off-by: hagen1778 <roman@victoriametrics.com> * app/vmalert: simplify API for /api/v1/rule Signed-off-by: hagen1778 <roman@victoriametrics.com> * app/vmalert: simplify API for /api/v1/rule Signed-off-by: hagen1778 <roman@victoriametrics.com> * app/vmalert: simplify API for /api/v1/rule Signed-off-by: hagen1778 <roman@victoriametrics.com> * app/vmalert: simplify API for /api/v1/rule Signed-off-by: hagen1778 <roman@victoriametrics.com> --------- Signed-off-by: hagen1778 <roman@victoriametrics.com> Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com> Co-authored-by: hagen1778 <roman@victoriametrics.com>
This commit is contained in:
parent
17900e39d7
commit
a28cc6ebec
@ -30,6 +30,7 @@ type AlertingRule struct {
|
|||||||
Annotations map[string]string
|
Annotations map[string]string
|
||||||
GroupID uint64
|
GroupID uint64
|
||||||
GroupName string
|
GroupName string
|
||||||
|
File string
|
||||||
EvalInterval time.Duration
|
EvalInterval time.Duration
|
||||||
Debug bool
|
Debug bool
|
||||||
|
|
||||||
@ -67,6 +68,7 @@ func NewAlertingRule(qb datasource.QuerierBuilder, group *Group, cfg config.Rule
|
|||||||
Annotations: cfg.Annotations,
|
Annotations: cfg.Annotations,
|
||||||
GroupID: group.ID(),
|
GroupID: group.ID(),
|
||||||
GroupName: group.Name,
|
GroupName: group.Name,
|
||||||
|
File: group.File,
|
||||||
EvalInterval: group.Interval,
|
EvalInterval: group.Interval,
|
||||||
Debug: cfg.Debug,
|
Debug: cfg.Debug,
|
||||||
q: qb.BuildWithParams(datasource.QuerierParams{
|
q: qb.BuildWithParams(datasource.QuerierParams{
|
||||||
|
@ -17,12 +17,14 @@ import (
|
|||||||
// to evaluate configured Expression and
|
// to evaluate configured Expression and
|
||||||
// return TimeSeries as result.
|
// return TimeSeries as result.
|
||||||
type RecordingRule struct {
|
type RecordingRule struct {
|
||||||
Type config.Type
|
Type config.Type
|
||||||
RuleID uint64
|
RuleID uint64
|
||||||
Name string
|
Name string
|
||||||
Expr string
|
Expr string
|
||||||
Labels map[string]string
|
Labels map[string]string
|
||||||
GroupID uint64
|
GroupID uint64
|
||||||
|
GroupName string
|
||||||
|
File string
|
||||||
|
|
||||||
q datasource.Querier
|
q datasource.Querier
|
||||||
|
|
||||||
@ -52,13 +54,15 @@ func (rr *RecordingRule) ID() uint64 {
|
|||||||
// NewRecordingRule creates a new RecordingRule
|
// NewRecordingRule creates a new RecordingRule
|
||||||
func NewRecordingRule(qb datasource.QuerierBuilder, group *Group, cfg config.Rule) *RecordingRule {
|
func NewRecordingRule(qb datasource.QuerierBuilder, group *Group, cfg config.Rule) *RecordingRule {
|
||||||
rr := &RecordingRule{
|
rr := &RecordingRule{
|
||||||
Type: group.Type,
|
Type: group.Type,
|
||||||
RuleID: cfg.ID,
|
RuleID: cfg.ID,
|
||||||
Name: cfg.Record,
|
Name: cfg.Record,
|
||||||
Expr: cfg.Expr,
|
Expr: cfg.Expr,
|
||||||
Labels: cfg.Labels,
|
Labels: cfg.Labels,
|
||||||
GroupID: group.ID(),
|
GroupID: group.ID(),
|
||||||
metrics: &recordingRuleMetrics{},
|
GroupName: group.Name,
|
||||||
|
File: group.File,
|
||||||
|
metrics: &recordingRuleMetrics{},
|
||||||
q: qb.BuildWithParams(datasource.QuerierParams{
|
q: qb.BuildWithParams(datasource.QuerierParams{
|
||||||
DataSourceType: group.Type.String(),
|
DataSourceType: group.Type.String(),
|
||||||
EvaluationInterval: group.Interval,
|
EvaluationInterval: group.Interval,
|
||||||
|
@ -43,26 +43,26 @@ type ruleState struct {
|
|||||||
// StateEntry stores rule's execution states
|
// StateEntry stores rule's execution states
|
||||||
type StateEntry struct {
|
type StateEntry struct {
|
||||||
// stores last moment of time rule.Exec was called
|
// stores last moment of time rule.Exec was called
|
||||||
Time time.Time
|
Time time.Time `json:"time"`
|
||||||
// stores the timesteamp with which rule.Exec was called
|
// stores the timesteamp with which rule.Exec was called
|
||||||
At time.Time
|
At time.Time `json:"at"`
|
||||||
// stores the duration of the last rule.Exec call
|
// stores the duration of the last rule.Exec call
|
||||||
Duration time.Duration
|
Duration time.Duration `json:"duration"`
|
||||||
// stores last error that happened in Exec func
|
// stores last error that happened in Exec func
|
||||||
// resets on every successful Exec
|
// resets on every successful Exec
|
||||||
// may be used as Health ruleState
|
// may be used as Health ruleState
|
||||||
Err error
|
Err error `json:"error"`
|
||||||
// stores the number of samples returned during
|
// stores the number of samples returned during
|
||||||
// the last evaluation
|
// the last evaluation
|
||||||
Samples int
|
Samples int `json:"samples"`
|
||||||
// stores the number of time series fetched during
|
// stores the number of time series fetched during
|
||||||
// the last evaluation.
|
// the last evaluation.
|
||||||
// Is supported by VictoriaMetrics only, starting from v1.90.0
|
// Is supported by VictoriaMetrics only, starting from v1.90.0
|
||||||
// If seriesFetched == nil, then this attribute was missing in
|
// If seriesFetched == nil, then this attribute was missing in
|
||||||
// datasource response (unsupported).
|
// datasource response (unsupported).
|
||||||
SeriesFetched *int
|
SeriesFetched *int `json:"series_fetched"`
|
||||||
// stores the curl command reflecting the HTTP request used during rule.Exec
|
// stores the curl command reflecting the HTTP request used during rule.Exec
|
||||||
Curl string
|
Curl string `json:"curl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLastEntry returns latest stateEntry of rule
|
// GetLastEntry returns latest stateEntry of rule
|
||||||
|
@ -132,6 +132,24 @@ func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool {
|
|||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write(data)
|
w.Write(data)
|
||||||
return true
|
return true
|
||||||
|
case "/vmalert/api/v1/rule", "/api/v1/rule":
|
||||||
|
rule, err := rh.getRule(r)
|
||||||
|
if err != nil {
|
||||||
|
httpserver.Errorf(w, r, "%s", err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
rwu := apiRuleWithUpdates{
|
||||||
|
apiRule: rule,
|
||||||
|
StateUpdates: rule.Updates,
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(rwu)
|
||||||
|
if err != nil {
|
||||||
|
httpserver.Errorf(w, r, "failed to marshal rule: %s", err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write(data)
|
||||||
|
return true
|
||||||
case "/-/reload":
|
case "/-/reload":
|
||||||
logger.Infof("api config reload was called, sending sighup")
|
logger.Infof("api config reload was called, sending sighup")
|
||||||
procutil.SelfSIGHUP()
|
procutil.SelfSIGHUP()
|
||||||
|
@ -143,6 +143,28 @@ func TestHandler(t *testing.T) {
|
|||||||
t.Errorf("expected 1 group got %d", length)
|
t.Errorf("expected 1 group got %d", length)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
t.Run("/api/v1/rule?ruleID&groupID", func(t *testing.T) {
|
||||||
|
expRule := ruleToAPI(ar)
|
||||||
|
gotRule := apiRule{}
|
||||||
|
getResp(ts.URL+"/"+expRule.APILink(), &gotRule, 200)
|
||||||
|
|
||||||
|
if expRule.ID != gotRule.ID {
|
||||||
|
t.Errorf("expected to get Rule %q; got %q instead", expRule.ID, gotRule.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
gotRule = apiRule{}
|
||||||
|
getResp(ts.URL+"/vmalert/"+expRule.APILink(), &gotRule, 200)
|
||||||
|
|
||||||
|
if expRule.ID != gotRule.ID {
|
||||||
|
t.Errorf("expected to get Rule %q; got %q instead", expRule.ID, gotRule.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
gotRuleWithUpdates := apiRuleWithUpdates{}
|
||||||
|
getResp(ts.URL+"/"+expRule.APILink(), &gotRuleWithUpdates, 200)
|
||||||
|
if gotRuleWithUpdates.StateUpdates == nil || len(gotRuleWithUpdates.StateUpdates) < 1 {
|
||||||
|
t.Fatalf("expected %+v to have state updates field not empty", gotRuleWithUpdates.StateUpdates)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEmptyResponse(t *testing.T) {
|
func TestEmptyResponse(t *testing.T) {
|
||||||
|
@ -151,6 +151,10 @@ type apiRule struct {
|
|||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
// GroupID is an unique Group's ID
|
// GroupID is an unique Group's ID
|
||||||
GroupID string `json:"group_id"`
|
GroupID string `json:"group_id"`
|
||||||
|
// GroupName is Group name rule belong to
|
||||||
|
GroupName string `json:"group_name"`
|
||||||
|
// File is file name where rule is defined
|
||||||
|
File string `json:"file"`
|
||||||
// Debug shows whether debug mode is enabled
|
// Debug shows whether debug mode is enabled
|
||||||
Debug bool `json:"debug"`
|
Debug bool `json:"debug"`
|
||||||
|
|
||||||
@ -160,6 +164,19 @@ type apiRule struct {
|
|||||||
Updates []rule.StateEntry `json:"-"`
|
Updates []rule.StateEntry `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apiRuleWithUpdates represents apiRule but with extra fields for marshalling
|
||||||
|
type apiRuleWithUpdates struct {
|
||||||
|
apiRule
|
||||||
|
// Updates contains the ordered list of recorded ruleStateEntry objects
|
||||||
|
StateUpdates []rule.StateEntry `json:"updates,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// APILink returns a link to the rule's JSON representation.
|
||||||
|
func (ar apiRule) APILink() string {
|
||||||
|
return fmt.Sprintf("api/v1/rule?%s=%s&%s=%s",
|
||||||
|
paramGroupID, ar.GroupID, paramRuleID, ar.ID)
|
||||||
|
}
|
||||||
|
|
||||||
// WebLink returns a link to the alert which can be used in UI.
|
// WebLink returns a link to the alert which can be used in UI.
|
||||||
func (ar apiRule) WebLink() string {
|
func (ar apiRule) WebLink() string {
|
||||||
return fmt.Sprintf("rule?%s=%s&%s=%s",
|
return fmt.Sprintf("rule?%s=%s&%s=%s",
|
||||||
@ -227,8 +244,10 @@ func alertingToAPI(ar *rule.AlertingRule) apiRule {
|
|||||||
Debug: ar.Debug,
|
Debug: ar.Debug,
|
||||||
|
|
||||||
// encode as strings to avoid rounding in JSON
|
// encode as strings to avoid rounding in JSON
|
||||||
ID: fmt.Sprintf("%d", ar.ID()),
|
ID: fmt.Sprintf("%d", ar.ID()),
|
||||||
GroupID: fmt.Sprintf("%d", ar.GroupID),
|
GroupID: fmt.Sprintf("%d", ar.GroupID),
|
||||||
|
GroupName: ar.GroupName,
|
||||||
|
File: ar.File,
|
||||||
}
|
}
|
||||||
if lastState.Err != nil {
|
if lastState.Err != nil {
|
||||||
r.LastError = lastState.Err.Error()
|
r.LastError = lastState.Err.Error()
|
||||||
|
@ -37,6 +37,7 @@ The sandbox cluster installation is running under the constant load generated by
|
|||||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): show all the dropped targets together with the reason why they are dropped at `http://vmagent:8429/service-discovery` page. Previously targets, which were dropped because of [target sharding](https://docs.victoriametrics.com/vmagent.html#scraping-big-number-of-targets) weren't displayed on this page. This could complicate service discovery debugging. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5389).
|
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): show all the dropped targets together with the reason why they are dropped at `http://vmagent:8429/service-discovery` page. Previously targets, which were dropped because of [target sharding](https://docs.victoriametrics.com/vmagent.html#scraping-big-number-of-targets) weren't displayed on this page. This could complicate service discovery debugging. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5389).
|
||||||
* FEATURE: reduce the default value for `-import.maxLineLen` command-line flag from 100MB to 10MB in order to prevent excessive memory usage during data import via [/api/v1/import](https://docs.victoriametrics.com/#how-to-import-data-in-json-line-format).
|
* FEATURE: reduce the default value for `-import.maxLineLen` command-line flag from 100MB to 10MB in order to prevent excessive memory usage during data import via [/api/v1/import](https://docs.victoriametrics.com/#how-to-import-data-in-json-line-format).
|
||||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): add `keep_if_contains` and `drop_if_contains` relabeling actions. See [these docs](https://docs.victoriametrics.com/vmagent.html#relabeling-enhancements) for details.
|
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): add `keep_if_contains` and `drop_if_contains` relabeling actions. See [these docs](https://docs.victoriametrics.com/vmagent.html#relabeling-enhancements) for details.
|
||||||
|
* FEATURE: [vmalert](https://docs.victoriametrics.com/vmalert.html): provide `/vmalert/api/v1/rule` and `/api/v1/rule` API endpoints to get the rule object in JSON format. See [these docs](https://docs.victoriametrics.com/vmalert.html#web) for details.
|
||||||
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): add [day_of_year()](https://docs.victoriametrics.com/MetricsQL.html#day_of_year) function, which returns the day of the year for each of the given unix timestamps. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5345) for details. Thanks to @luckyxiaoqiang for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5368/).
|
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): add [day_of_year()](https://docs.victoriametrics.com/MetricsQL.html#day_of_year) function, which returns the day of the year for each of the given unix timestamps. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5345) for details. Thanks to @luckyxiaoqiang for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5368/).
|
||||||
* FEATURE: all VictoriaMetrics binaries: expose additional metrics at `/metrics` page, which may simplify debugging of VictoriaMetrics components (see [this feature request](https://github.com/VictoriaMetrics/metrics/issues/54)):
|
* FEATURE: all VictoriaMetrics binaries: expose additional metrics at `/metrics` page, which may simplify debugging of VictoriaMetrics components (see [this feature request](https://github.com/VictoriaMetrics/metrics/issues/54)):
|
||||||
* `go_sched_latencies_seconds` - the [histogram](https://docs.victoriametrics.com/keyConcepts.html#histogram), which shows the time goroutines have spent in runnable state before actually running. Big values point to the lack of CPU time for the current workload.
|
* `go_sched_latencies_seconds` - the [histogram](https://docs.victoriametrics.com/keyConcepts.html#histogram), which shows the time goroutines have spent in runnable state before actually running. Big values point to the lack of CPU time for the current workload.
|
||||||
|
@ -659,6 +659,7 @@ or time series modification via [relabeling](https://docs.victoriametrics.com/vm
|
|||||||
Used as alert source in AlertManager.
|
Used as alert source in AlertManager.
|
||||||
* `http://<vmalert-addr>/vmalert/alert?group_id=<group_id>&alert_id=<alert_id>` - get alert status in web UI.
|
* `http://<vmalert-addr>/vmalert/alert?group_id=<group_id>&alert_id=<alert_id>` - get alert status in web UI.
|
||||||
* `http://<vmalert-addr>/vmalert/rule?group_id=<group_id>&rule_id=<rule_id>` - get rule status in web UI.
|
* `http://<vmalert-addr>/vmalert/rule?group_id=<group_id>&rule_id=<rule_id>` - get rule status in web UI.
|
||||||
|
* `http://<vmalert-addr>/vmalert/api/v1/rule?group_id=<group_id>&alert_id=<alert_id>` - get rule status in JSON format.
|
||||||
* `http://<vmalert-addr>/metrics` - application metrics.
|
* `http://<vmalert-addr>/metrics` - application metrics.
|
||||||
* `http://<vmalert-addr>/-/reload` - hot configuration reload.
|
* `http://<vmalert-addr>/-/reload` - hot configuration reload.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user