| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695 |
- // Copyright 2019 Yunion
- //
- // 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 monitor
- import (
- "fmt"
- "strings"
- "time"
- "yunion.io/x/jsonutils"
- "yunion.io/x/pkg/utils"
- "yunion.io/x/onecloud/pkg/apis/monitor"
- "yunion.io/x/onecloud/pkg/monitor/tsdb"
- )
- // AlertConfig is a helper to generate monitor service alert related api input
- type AlertConfig struct {
- name string
- frequencyStr string
- frequency int64
- forTime int64
- level string
- enabled bool
- conditions []*AlertCondition
- execErrorState string
- noDataState string
- UsedBy string
- }
- func NewAlertConfig(name string, frequency string, enabled bool) (*AlertConfig, error) {
- freq, err := time.ParseDuration(frequency)
- if err != nil {
- return nil, err
- }
- input := &AlertConfig{
- name: name,
- frequencyStr: frequency,
- frequency: int64(freq / time.Second),
- level: "",
- enabled: enabled,
- conditions: make([]*AlertCondition, 0),
- }
- return input, nil
- }
- func (c *AlertConfig) ExecutionErrorState(s string) *AlertConfig {
- c.execErrorState = s
- return c
- }
- func (c *AlertConfig) NoDataState(s string) *AlertConfig {
- c.noDataState = s
- return c
- }
- func (c *AlertConfig) Level(l string) *AlertConfig {
- c.level = l
- return c
- }
- func (c *AlertConfig) Enable(e bool) *AlertConfig {
- c.enabled = e
- return c
- }
- func (c *AlertConfig) ToAlertCreateInput() monitor.AlertCreateInput {
- return monitor.AlertCreateInput{
- Name: c.name,
- Frequency: c.frequency,
- Settings: c.ToAlertSetting(),
- Enabled: &c.enabled,
- Level: c.level,
- For: c.forTime,
- ExecutionErrorState: c.execErrorState,
- NoDataState: c.noDataState,
- UsedBy: c.UsedBy,
- }
- }
- func (c *AlertConfig) ToCommonMetricInputQuery() monitor.CommonMetricInputQuery {
- conds := make([]*monitor.CommonAlertQuery, len(c.conditions))
- for i, cc := range c.conditions {
- tmp := cc.ToCommonAlertQuery()
- conds[i] = &tmp
- }
- return monitor.CommonMetricInputQuery{
- MetricQuery: conds,
- }
- }
- func (c *AlertConfig) ToCommonAlertCreateInput(bi *monitor.CommonAlertCreateBaseInput) monitor.CommonAlertCreateInput {
- mq := c.ToCommonMetricInputQuery()
- ai := c.ToAlertCreateInput()
- if bi == nil {
- bi = new(monitor.CommonAlertCreateBaseInput)
- }
- input := monitor.CommonAlertCreateInput{
- CommonMetricInputQuery: mq,
- AlertCreateInput: ai,
- CommonAlertCreateBaseInput: *bi,
- Period: c.frequencyStr,
- }
- input.UsedBy = c.UsedBy
- return input
- }
- func (c *AlertConfig) ToAlertSetting() monitor.AlertSetting {
- conds := make([]monitor.AlertCondition, len(c.conditions))
- for i, cc := range c.conditions {
- conds[i] = cc.ToCondition()
- }
- return monitor.AlertSetting{
- Conditions: conds,
- }
- }
- func (c *AlertConfig) Condition(database string, measurement string) *AlertCondition {
- cc := NewAlertCondition(database, measurement)
- c.conditions = append(c.conditions, cc)
- return cc
- }
- func (c *AlertConfig) AND(cs ...*AlertCondition) *AlertConfig {
- if len(cs) == 0 {
- return c
- }
- for _, cond := range cs {
- cond.setOperator("AND")
- }
- return c
- }
- func (c *AlertConfig) OR(cs ...*AlertCondition) *AlertConfig {
- if len(cs) == 0 {
- return c
- }
- for _, cond := range cs {
- cond.setOperator("OR")
- }
- return c
- }
- type AlertCondition struct {
- operator string
- reducer *monitor.Condition
- evaluator *monitor.Condition
- query *AlertQuery
- }
- func NewAlertCondition(
- database string,
- measurement string,
- ) *AlertCondition {
- c := &AlertCondition{
- query: NewAlertQuery(database, measurement),
- }
- // set default avg reducer
- c.Avg()
- return c
- }
- func (c *AlertCondition) ToCondition() monitor.AlertCondition {
- return monitor.AlertCondition{
- Type: "query",
- Query: c.query.ToAlertQuery(),
- Reducer: *c.reducer,
- Evaluator: *c.evaluator,
- Operator: c.operator,
- }
- }
- func (c *AlertCondition) ToCommonAlertQuery() monitor.CommonAlertQuery {
- aq := c.query.ToAlertQuery()
- eval := string(c.evaluator.Type)
- if !utils.IsInStringArray(eval, []string{"lt", "gt", "eq"}) {
- panic(fmt.Sprintf("Invalid evaluator %q", eval))
- }
- var comp string
- switch eval {
- case "lt":
- comp = "<="
- case "gt":
- comp = ">="
- case "eq":
- comp = "=="
- }
- return monitor.CommonAlertQuery{
- AlertQuery: &aq,
- Reduce: c.reducer.Type,
- Comparator: comp,
- Threshold: c.evaluator.Params[0],
- // TODO: figure out what's the meaning of FieldOpt
- FieldOpt: "",
- ConditionType: "query",
- }
- }
- func (c *AlertCondition) setOperator(op string) *AlertCondition {
- c.operator = op
- return c
- }
- func (c *AlertCondition) setReducer(typ string, params ...float64) *AlertCondition {
- c.reducer = &monitor.Condition{
- Type: typ,
- }
- c.reducer.Params = params
- return c
- }
- func (c *AlertCondition) Avg() *AlertCondition {
- return c.setReducer("avg")
- }
- func (c *AlertCondition) Sum() *AlertCondition {
- return c.setReducer("sum")
- }
- func (c *AlertCondition) Min() *AlertCondition {
- return c.setReducer("min")
- }
- func (c *AlertCondition) Max() *AlertCondition {
- return c.setReducer("max")
- }
- func (c *AlertCondition) Count() *AlertCondition {
- return c.setReducer("count")
- }
- func (c *AlertCondition) Last() *AlertCondition {
- return c.setReducer("last")
- }
- func (c *AlertCondition) Median() *AlertCondition {
- return c.setReducer("median")
- }
- func (c *AlertCondition) setEvaluator(typ string, threshold float64) *AlertCondition {
- c.evaluator = &monitor.Condition{
- Type: typ,
- Params: []float64{threshold},
- }
- return c
- }
- // LessThan is evaluator part
- func (c *AlertCondition) LT(threshold float64) *AlertCondition {
- return c.setEvaluator("lt", threshold)
- }
- // GreaterThan is evaluator part
- func (c *AlertCondition) GT(threshold float64) *AlertCondition {
- return c.setEvaluator("gt", threshold)
- }
- func (c *AlertCondition) Query() *AlertQuery {
- return c.query
- }
- type AlertQuery struct {
- from string
- to string
- alias string
- tz string
- database string
- measurement string
- interval string
- policy string
- resultFormat string
- selects *AlertQuerySelects
- where *AlertQueryWhere
- groupBy *AlertQueryGroupBy
- resultReducer *monitor.Condition
- resultReducerOrder monitor.ResultReducerOrder
- }
- func NewAlertQuery(database string, measurement string) *AlertQuery {
- q := &AlertQuery{
- selects: new(AlertQuerySelects),
- where: new(AlertQueryWhere),
- groupBy: new(AlertQueryGroupBy),
- }
- q = q.Database(database).Measurement(measurement)
- return q
- }
- func (q *AlertQuery) ToAlertQuery() monitor.AlertQuery {
- return monitor.AlertQuery{
- Model: q.ToMetricQuery(),
- From: q.from,
- To: q.to,
- }
- }
- func (q *AlertQuery) ToMetricQuery() monitor.MetricQuery {
- return monitor.MetricQuery{
- Alias: q.alias,
- Tz: q.tz,
- Database: q.database,
- Measurement: q.measurement,
- Tags: q.where.ToTags(),
- GroupBy: q.groupBy.ToGroupBy(),
- Selects: q.selects.ToSelects(),
- Interval: q.interval,
- Policy: q.policy,
- ResultFormat: q.resultFormat,
- }
- }
- func (q *AlertQuery) ToTsdbQuery() *tsdb.TsdbQuery {
- timeRange := tsdb.NewTimeRange(q.from, q.to)
- tsdbQ := &tsdb.TsdbQuery{
- TimeRange: timeRange,
- Queries: []*tsdb.Query{
- {
- MetricQuery: q.ToMetricQuery(),
- },
- },
- }
- return tsdbQ
- }
- func (q *AlertQuery) From(from string) *AlertQuery {
- q.from = from
- return q
- }
- func (q *AlertQuery) To(to string) *AlertQuery {
- q.to = to
- return q
- }
- func (q *AlertQuery) Alias(alias string) *AlertQuery {
- q.alias = alias
- return q
- }
- func (q *AlertQuery) Tz(tz string) *AlertQuery {
- q.tz = tz
- return q
- }
- func (q *AlertQuery) Database(db string) *AlertQuery {
- q.database = db
- return q
- }
- func (q *AlertQuery) Measurement(m string) *AlertQuery {
- q.measurement = m
- return q
- }
- func (q *AlertQuery) Interval(i string) *AlertQuery {
- q.interval = i
- return q
- }
- func (q *AlertQuery) Policy(p string) *AlertQuery {
- q.policy = p
- return q
- }
- func (q *AlertQuery) Selects() *AlertQuerySelects {
- q.selects = &AlertQuerySelects{
- parts: make([]*AlertQuerySelect, 0),
- }
- return q.selects
- }
- func (q *AlertQuery) Where() *AlertQueryWhere {
- w := &AlertQueryWhere{
- parts: make([]monitor.MetricQueryTag, 0),
- }
- w.AND()
- q.where = w
- return w
- }
- func (q *AlertQuery) GroupBy() *AlertQueryGroupBy {
- g := &AlertQueryGroupBy{parts: make([]monitor.MetricQueryPart, 0)}
- q.groupBy = g
- return g
- }
- func (q *AlertQuery) Reducer(rType string, params []float64) *AlertQuery {
- q.resultReducer = &monitor.Condition{
- Type: rType,
- Params: params,
- }
- return q
- }
- func (q *AlertQuery) ReducerOrder(rType monitor.ResultReducerOrder) *AlertQuery {
- q.resultReducerOrder = rType
- return q
- }
- type AlertQuerySelects struct {
- parts []*AlertQuerySelect
- }
- type AlertQuerySelect struct {
- monitor.MetricQuerySelect
- }
- func (s *AlertQuerySelects) Select(fieldName string) *AlertQuerySelect {
- if s.parts == nil {
- s.parts = make([]*AlertQuerySelect, 0)
- }
- sel := make([]monitor.MetricQueryPart, 0)
- sel = append(sel, monitor.NewMetricQueryPartField(fieldName))
- part := &AlertQuerySelect{sel}
- s.parts = append(s.parts, part)
- return part
- }
- func (s *AlertQuerySelects) ToSelects() []monitor.MetricQuerySelect {
- ret := make([]monitor.MetricQuerySelect, len(s.parts))
- for i, p := range s.parts {
- ret[i] = p.MetricQuerySelect
- }
- return ret
- }
- func (s *AlertQuerySelect) addPart(p monitor.MetricQueryPart) *AlertQuerySelect {
- s.MetricQuerySelect = append(s.MetricQuerySelect, p)
- return s
- }
- // Aggregations method
- func (s *AlertQuerySelect) MEAN() *AlertQuerySelect {
- return s.addPart(monitor.NewMetricQueryPartMean())
- }
- func (s *AlertQuerySelect) COUNT() *AlertQuerySelect {
- return s.addPart(monitor.NewMetricQueryPartCount())
- }
- func (s *AlertQuerySelect) DISTINCT() *AlertQuerySelect {
- return s.addPart(monitor.NewMetricQueryPartDistinct())
- }
- func (s *AlertQuerySelect) SUM() *AlertQuerySelect {
- return s.addPart(monitor.NewMetricQueryPartSum())
- }
- func (s *AlertQuerySelect) MIN() *AlertQuerySelect {
- return s.addPart(monitor.NewMetricQueryPartMin())
- }
- func (s *AlertQuerySelect) MAX() *AlertQuerySelect {
- return s.addPart(monitor.NewMetricQueryPartMax())
- }
- func (s *AlertQuerySelect) LAST() *AlertQuerySelect {
- return s.addPart(monitor.NewMetricQueryPartLast())
- }
- // AS is alias method
- func (s *AlertQuerySelect) AS(alias string) *AlertQuerySelect {
- return s.addPart(monitor.NewMetricQueryPartAS(alias))
- }
- // MATH method
- func (s *AlertQuerySelect) MATH(op string, val string) *AlertQuerySelect {
- return s.addPart(monitor.NewMetricQueryPartMath(op, val))
- }
- type AlertQueryWhere struct {
- parts []monitor.MetricQueryTag
- cond string
- }
- func (w *AlertQueryWhere) add(tags ...monitor.MetricQueryTag) *AlertQueryWhere {
- w.parts = append(w.parts, tags...)
- return w
- }
- func (w *AlertQueryWhere) condAdd(cond string, tags ...monitor.MetricQueryTag) *AlertQueryWhere {
- for i := range tags {
- tags[i].Condition = cond
- }
- w.add(tags...)
- return w
- }
- func (w *AlertQueryWhere) filter(op string, key string, value string) *AlertQueryWhere {
- if len(w.parts) == 0 {
- w.add(w.newTag(op, key, value))
- return w
- }
- return w.condAdd(w.cond, w.newTag(op, key, value))
- }
- func (w *AlertQueryWhere) Equal(key string, value string) *AlertQueryWhere {
- return w.filter("=", key, value)
- }
- func (w *AlertQueryWhere) NotEqual(key string, value string) *AlertQueryWhere {
- return w.filter("!=", key, value)
- }
- func (w *AlertQueryWhere) LT(key string, value string) *AlertQueryWhere {
- return w.filter("<", key, value)
- }
- func (w *AlertQueryWhere) GT(key string, value string) *AlertQueryWhere {
- return w.filter(">", key, value)
- }
- func (w *AlertQueryWhere) AND() *AlertQueryWhere {
- w.cond = "AND"
- return w
- }
- func (w *AlertQueryWhere) OR() *AlertQueryWhere {
- w.cond = "OR"
- return w
- }
- func (w *AlertQueryWhere) REGEX(key, val string) *AlertQueryWhere {
- return w.filter("=~", key, fmt.Sprintf("/%s/", val))
- }
- func (w *AlertQueryWhere) IN(key string, vals []string) *AlertQueryWhere {
- if len(vals) == 0 {
- return w
- }
- valStr := strings.Join(vals, "|")
- return w.REGEX(key, valStr)
- }
- func (w *AlertQueryWhere) AddTag(tag *monitor.MetricQueryTag) *AlertQueryWhere {
- if tag == nil {
- return w
- }
- if tag.Condition != "" {
- w.cond = tag.Condition
- }
- return w.filter(tag.Operator, tag.Key, tag.Value)
- }
- func (w *AlertQueryWhere) newTag(op string, key string, value string) monitor.MetricQueryTag {
- return monitor.MetricQueryTag{
- Key: key,
- Operator: op,
- Value: value,
- }
- }
- func (w *AlertQueryWhere) ToTags() []monitor.MetricQueryTag {
- return w.parts
- }
- type AlertQueryGroupBy struct {
- parts []monitor.MetricQueryPart
- }
- func (g *AlertQueryGroupBy) addPart(typ string, params ...string) *AlertQueryGroupBy {
- g.parts = append(g.parts, monitor.MetricQueryPart{
- Type: typ,
- Params: params,
- })
- return g
- }
- func (g *AlertQueryGroupBy) TIME(val string) *AlertQueryGroupBy {
- return g.addPart("time", val)
- }
- func (g *AlertQueryGroupBy) TAG(val string) *AlertQueryGroupBy {
- return g.addPart("tag", val)
- }
- func (g *AlertQueryGroupBy) FILL_NULL() *AlertQueryGroupBy {
- return g.FILL("null")
- }
- func (g *AlertQueryGroupBy) FILL(val string) *AlertQueryGroupBy {
- return g.addPart("fill", val)
- }
- func (g *AlertQueryGroupBy) ToGroupBy() []monitor.MetricQueryPart {
- return g.parts
- }
- type MetricQueryInput struct {
- from string `json:"from"`
- to string `json:"to"`
- scope string `json:"scope"`
- slimit string `json:"slimit"`
- soffset string `json:"soffset"`
- unit bool `json:"unit"`
- interval string `json:"interval"`
- domainId string `json:"domain_id"`
- projectId string `json:"project_id"`
- showMeta bool `json:"show_meta"`
- skipCheckSeries bool `json:"skip_check_series"`
- query *AlertQuery
- }
- func NewMetricQueryInput(measurement string) *MetricQueryInput {
- return NewMetricQueryInputWithDB("", measurement)
- }
- func NewMetricQueryInputWithDB(db string, measurement string) *MetricQueryInput {
- return &MetricQueryInput{
- query: NewAlertQuery(db, measurement),
- }
- }
- func (input *MetricQueryInput) Interval(interval string) *MetricQueryInput {
- input.interval = interval
- return input
- }
- func (input *MetricQueryInput) From(from time.Time) *MetricQueryInput {
- input.from = fmt.Sprintf("%d", from.UnixMilli())
- return input
- }
- func (input *MetricQueryInput) To(to time.Time) *MetricQueryInput {
- input.to = fmt.Sprintf("%d", to.UnixMilli())
- return input
- }
- func (input *MetricQueryInput) Scope(scope string) *MetricQueryInput {
- input.scope = scope
- return input
- }
- func (input *MetricQueryInput) SkipCheckSeries(skip bool) *MetricQueryInput {
- input.skipCheckSeries = skip
- return input
- }
- func (input *MetricQueryInput) Selects() *AlertQuerySelects {
- return input.query.Selects()
- }
- func (input *MetricQueryInput) Where() *AlertQueryWhere {
- return input.query.Where()
- }
- func (input *MetricQueryInput) GroupBy() *AlertQueryGroupBy {
- return input.query.GroupBy()
- }
- func (input *MetricQueryInput) Reducer(rType string, params []float64) *AlertQuery {
- return input.query.Reducer(rType, params)
- }
- func (input *MetricQueryInput) ToQueryData() *monitor.MetricQueryInput {
- data := &monitor.MetricQueryInput{
- From: input.from,
- To: input.to,
- Scope: input.scope,
- Slimit: input.slimit,
- Soffset: input.soffset,
- Unit: input.unit,
- Interval: input.interval,
- DomainId: input.domainId,
- ProjectId: input.projectId,
- ShowMeta: input.showMeta,
- SkipCheckSeries: input.skipCheckSeries,
- }
- data.MetricQuery = []*monitor.AlertQuery{
- {
- Model: input.query.ToMetricQuery(),
- ResultReducer: input.query.resultReducer,
- ResultReducerOrder: input.query.resultReducerOrder,
- },
- }
- jsonData := jsonutils.Marshal(data).(*jsonutils.JSONDict)
- digest := monitor.DigestQuerySignature(jsonData)
- data.Signature = digest
- return data
- }
|