helper.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package monitor
  15. import (
  16. "fmt"
  17. "strings"
  18. "time"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/pkg/utils"
  21. "yunion.io/x/onecloud/pkg/apis/monitor"
  22. "yunion.io/x/onecloud/pkg/monitor/tsdb"
  23. )
  24. // AlertConfig is a helper to generate monitor service alert related api input
  25. type AlertConfig struct {
  26. name string
  27. frequencyStr string
  28. frequency int64
  29. forTime int64
  30. level string
  31. enabled bool
  32. conditions []*AlertCondition
  33. execErrorState string
  34. noDataState string
  35. UsedBy string
  36. }
  37. func NewAlertConfig(name string, frequency string, enabled bool) (*AlertConfig, error) {
  38. freq, err := time.ParseDuration(frequency)
  39. if err != nil {
  40. return nil, err
  41. }
  42. input := &AlertConfig{
  43. name: name,
  44. frequencyStr: frequency,
  45. frequency: int64(freq / time.Second),
  46. level: "",
  47. enabled: enabled,
  48. conditions: make([]*AlertCondition, 0),
  49. }
  50. return input, nil
  51. }
  52. func (c *AlertConfig) ExecutionErrorState(s string) *AlertConfig {
  53. c.execErrorState = s
  54. return c
  55. }
  56. func (c *AlertConfig) NoDataState(s string) *AlertConfig {
  57. c.noDataState = s
  58. return c
  59. }
  60. func (c *AlertConfig) Level(l string) *AlertConfig {
  61. c.level = l
  62. return c
  63. }
  64. func (c *AlertConfig) Enable(e bool) *AlertConfig {
  65. c.enabled = e
  66. return c
  67. }
  68. func (c *AlertConfig) ToAlertCreateInput() monitor.AlertCreateInput {
  69. return monitor.AlertCreateInput{
  70. Name: c.name,
  71. Frequency: c.frequency,
  72. Settings: c.ToAlertSetting(),
  73. Enabled: &c.enabled,
  74. Level: c.level,
  75. For: c.forTime,
  76. ExecutionErrorState: c.execErrorState,
  77. NoDataState: c.noDataState,
  78. UsedBy: c.UsedBy,
  79. }
  80. }
  81. func (c *AlertConfig) ToCommonMetricInputQuery() monitor.CommonMetricInputQuery {
  82. conds := make([]*monitor.CommonAlertQuery, len(c.conditions))
  83. for i, cc := range c.conditions {
  84. tmp := cc.ToCommonAlertQuery()
  85. conds[i] = &tmp
  86. }
  87. return monitor.CommonMetricInputQuery{
  88. MetricQuery: conds,
  89. }
  90. }
  91. func (c *AlertConfig) ToCommonAlertCreateInput(bi *monitor.CommonAlertCreateBaseInput) monitor.CommonAlertCreateInput {
  92. mq := c.ToCommonMetricInputQuery()
  93. ai := c.ToAlertCreateInput()
  94. if bi == nil {
  95. bi = new(monitor.CommonAlertCreateBaseInput)
  96. }
  97. input := monitor.CommonAlertCreateInput{
  98. CommonMetricInputQuery: mq,
  99. AlertCreateInput: ai,
  100. CommonAlertCreateBaseInput: *bi,
  101. Period: c.frequencyStr,
  102. }
  103. input.UsedBy = c.UsedBy
  104. return input
  105. }
  106. func (c *AlertConfig) ToAlertSetting() monitor.AlertSetting {
  107. conds := make([]monitor.AlertCondition, len(c.conditions))
  108. for i, cc := range c.conditions {
  109. conds[i] = cc.ToCondition()
  110. }
  111. return monitor.AlertSetting{
  112. Conditions: conds,
  113. }
  114. }
  115. func (c *AlertConfig) Condition(database string, measurement string) *AlertCondition {
  116. cc := NewAlertCondition(database, measurement)
  117. c.conditions = append(c.conditions, cc)
  118. return cc
  119. }
  120. func (c *AlertConfig) AND(cs ...*AlertCondition) *AlertConfig {
  121. if len(cs) == 0 {
  122. return c
  123. }
  124. for _, cond := range cs {
  125. cond.setOperator("AND")
  126. }
  127. return c
  128. }
  129. func (c *AlertConfig) OR(cs ...*AlertCondition) *AlertConfig {
  130. if len(cs) == 0 {
  131. return c
  132. }
  133. for _, cond := range cs {
  134. cond.setOperator("OR")
  135. }
  136. return c
  137. }
  138. type AlertCondition struct {
  139. operator string
  140. reducer *monitor.Condition
  141. evaluator *monitor.Condition
  142. query *AlertQuery
  143. }
  144. func NewAlertCondition(
  145. database string,
  146. measurement string,
  147. ) *AlertCondition {
  148. c := &AlertCondition{
  149. query: NewAlertQuery(database, measurement),
  150. }
  151. // set default avg reducer
  152. c.Avg()
  153. return c
  154. }
  155. func (c *AlertCondition) ToCondition() monitor.AlertCondition {
  156. return monitor.AlertCondition{
  157. Type: "query",
  158. Query: c.query.ToAlertQuery(),
  159. Reducer: *c.reducer,
  160. Evaluator: *c.evaluator,
  161. Operator: c.operator,
  162. }
  163. }
  164. func (c *AlertCondition) ToCommonAlertQuery() monitor.CommonAlertQuery {
  165. aq := c.query.ToAlertQuery()
  166. eval := string(c.evaluator.Type)
  167. if !utils.IsInStringArray(eval, []string{"lt", "gt", "eq"}) {
  168. panic(fmt.Sprintf("Invalid evaluator %q", eval))
  169. }
  170. var comp string
  171. switch eval {
  172. case "lt":
  173. comp = "<="
  174. case "gt":
  175. comp = ">="
  176. case "eq":
  177. comp = "=="
  178. }
  179. return monitor.CommonAlertQuery{
  180. AlertQuery: &aq,
  181. Reduce: c.reducer.Type,
  182. Comparator: comp,
  183. Threshold: c.evaluator.Params[0],
  184. // TODO: figure out what's the meaning of FieldOpt
  185. FieldOpt: "",
  186. ConditionType: "query",
  187. }
  188. }
  189. func (c *AlertCondition) setOperator(op string) *AlertCondition {
  190. c.operator = op
  191. return c
  192. }
  193. func (c *AlertCondition) setReducer(typ string, params ...float64) *AlertCondition {
  194. c.reducer = &monitor.Condition{
  195. Type: typ,
  196. }
  197. c.reducer.Params = params
  198. return c
  199. }
  200. func (c *AlertCondition) Avg() *AlertCondition {
  201. return c.setReducer("avg")
  202. }
  203. func (c *AlertCondition) Sum() *AlertCondition {
  204. return c.setReducer("sum")
  205. }
  206. func (c *AlertCondition) Min() *AlertCondition {
  207. return c.setReducer("min")
  208. }
  209. func (c *AlertCondition) Max() *AlertCondition {
  210. return c.setReducer("max")
  211. }
  212. func (c *AlertCondition) Count() *AlertCondition {
  213. return c.setReducer("count")
  214. }
  215. func (c *AlertCondition) Last() *AlertCondition {
  216. return c.setReducer("last")
  217. }
  218. func (c *AlertCondition) Median() *AlertCondition {
  219. return c.setReducer("median")
  220. }
  221. func (c *AlertCondition) setEvaluator(typ string, threshold float64) *AlertCondition {
  222. c.evaluator = &monitor.Condition{
  223. Type: typ,
  224. Params: []float64{threshold},
  225. }
  226. return c
  227. }
  228. // LessThan is evaluator part
  229. func (c *AlertCondition) LT(threshold float64) *AlertCondition {
  230. return c.setEvaluator("lt", threshold)
  231. }
  232. // GreaterThan is evaluator part
  233. func (c *AlertCondition) GT(threshold float64) *AlertCondition {
  234. return c.setEvaluator("gt", threshold)
  235. }
  236. func (c *AlertCondition) Query() *AlertQuery {
  237. return c.query
  238. }
  239. type AlertQuery struct {
  240. from string
  241. to string
  242. alias string
  243. tz string
  244. database string
  245. measurement string
  246. interval string
  247. policy string
  248. resultFormat string
  249. selects *AlertQuerySelects
  250. where *AlertQueryWhere
  251. groupBy *AlertQueryGroupBy
  252. resultReducer *monitor.Condition
  253. resultReducerOrder monitor.ResultReducerOrder
  254. }
  255. func NewAlertQuery(database string, measurement string) *AlertQuery {
  256. q := &AlertQuery{
  257. selects: new(AlertQuerySelects),
  258. where: new(AlertQueryWhere),
  259. groupBy: new(AlertQueryGroupBy),
  260. }
  261. q = q.Database(database).Measurement(measurement)
  262. return q
  263. }
  264. func (q *AlertQuery) ToAlertQuery() monitor.AlertQuery {
  265. return monitor.AlertQuery{
  266. Model: q.ToMetricQuery(),
  267. From: q.from,
  268. To: q.to,
  269. }
  270. }
  271. func (q *AlertQuery) ToMetricQuery() monitor.MetricQuery {
  272. return monitor.MetricQuery{
  273. Alias: q.alias,
  274. Tz: q.tz,
  275. Database: q.database,
  276. Measurement: q.measurement,
  277. Tags: q.where.ToTags(),
  278. GroupBy: q.groupBy.ToGroupBy(),
  279. Selects: q.selects.ToSelects(),
  280. Interval: q.interval,
  281. Policy: q.policy,
  282. ResultFormat: q.resultFormat,
  283. }
  284. }
  285. func (q *AlertQuery) ToTsdbQuery() *tsdb.TsdbQuery {
  286. timeRange := tsdb.NewTimeRange(q.from, q.to)
  287. tsdbQ := &tsdb.TsdbQuery{
  288. TimeRange: timeRange,
  289. Queries: []*tsdb.Query{
  290. {
  291. MetricQuery: q.ToMetricQuery(),
  292. },
  293. },
  294. }
  295. return tsdbQ
  296. }
  297. func (q *AlertQuery) From(from string) *AlertQuery {
  298. q.from = from
  299. return q
  300. }
  301. func (q *AlertQuery) To(to string) *AlertQuery {
  302. q.to = to
  303. return q
  304. }
  305. func (q *AlertQuery) Alias(alias string) *AlertQuery {
  306. q.alias = alias
  307. return q
  308. }
  309. func (q *AlertQuery) Tz(tz string) *AlertQuery {
  310. q.tz = tz
  311. return q
  312. }
  313. func (q *AlertQuery) Database(db string) *AlertQuery {
  314. q.database = db
  315. return q
  316. }
  317. func (q *AlertQuery) Measurement(m string) *AlertQuery {
  318. q.measurement = m
  319. return q
  320. }
  321. func (q *AlertQuery) Interval(i string) *AlertQuery {
  322. q.interval = i
  323. return q
  324. }
  325. func (q *AlertQuery) Policy(p string) *AlertQuery {
  326. q.policy = p
  327. return q
  328. }
  329. func (q *AlertQuery) Selects() *AlertQuerySelects {
  330. q.selects = &AlertQuerySelects{
  331. parts: make([]*AlertQuerySelect, 0),
  332. }
  333. return q.selects
  334. }
  335. func (q *AlertQuery) Where() *AlertQueryWhere {
  336. w := &AlertQueryWhere{
  337. parts: make([]monitor.MetricQueryTag, 0),
  338. }
  339. w.AND()
  340. q.where = w
  341. return w
  342. }
  343. func (q *AlertQuery) GroupBy() *AlertQueryGroupBy {
  344. g := &AlertQueryGroupBy{parts: make([]monitor.MetricQueryPart, 0)}
  345. q.groupBy = g
  346. return g
  347. }
  348. func (q *AlertQuery) Reducer(rType string, params []float64) *AlertQuery {
  349. q.resultReducer = &monitor.Condition{
  350. Type: rType,
  351. Params: params,
  352. }
  353. return q
  354. }
  355. func (q *AlertQuery) ReducerOrder(rType monitor.ResultReducerOrder) *AlertQuery {
  356. q.resultReducerOrder = rType
  357. return q
  358. }
  359. type AlertQuerySelects struct {
  360. parts []*AlertQuerySelect
  361. }
  362. type AlertQuerySelect struct {
  363. monitor.MetricQuerySelect
  364. }
  365. func (s *AlertQuerySelects) Select(fieldName string) *AlertQuerySelect {
  366. if s.parts == nil {
  367. s.parts = make([]*AlertQuerySelect, 0)
  368. }
  369. sel := make([]monitor.MetricQueryPart, 0)
  370. sel = append(sel, monitor.NewMetricQueryPartField(fieldName))
  371. part := &AlertQuerySelect{sel}
  372. s.parts = append(s.parts, part)
  373. return part
  374. }
  375. func (s *AlertQuerySelects) ToSelects() []monitor.MetricQuerySelect {
  376. ret := make([]monitor.MetricQuerySelect, len(s.parts))
  377. for i, p := range s.parts {
  378. ret[i] = p.MetricQuerySelect
  379. }
  380. return ret
  381. }
  382. func (s *AlertQuerySelect) addPart(p monitor.MetricQueryPart) *AlertQuerySelect {
  383. s.MetricQuerySelect = append(s.MetricQuerySelect, p)
  384. return s
  385. }
  386. // Aggregations method
  387. func (s *AlertQuerySelect) MEAN() *AlertQuerySelect {
  388. return s.addPart(monitor.NewMetricQueryPartMean())
  389. }
  390. func (s *AlertQuerySelect) COUNT() *AlertQuerySelect {
  391. return s.addPart(monitor.NewMetricQueryPartCount())
  392. }
  393. func (s *AlertQuerySelect) DISTINCT() *AlertQuerySelect {
  394. return s.addPart(monitor.NewMetricQueryPartDistinct())
  395. }
  396. func (s *AlertQuerySelect) SUM() *AlertQuerySelect {
  397. return s.addPart(monitor.NewMetricQueryPartSum())
  398. }
  399. func (s *AlertQuerySelect) MIN() *AlertQuerySelect {
  400. return s.addPart(monitor.NewMetricQueryPartMin())
  401. }
  402. func (s *AlertQuerySelect) MAX() *AlertQuerySelect {
  403. return s.addPart(monitor.NewMetricQueryPartMax())
  404. }
  405. func (s *AlertQuerySelect) LAST() *AlertQuerySelect {
  406. return s.addPart(monitor.NewMetricQueryPartLast())
  407. }
  408. // AS is alias method
  409. func (s *AlertQuerySelect) AS(alias string) *AlertQuerySelect {
  410. return s.addPart(monitor.NewMetricQueryPartAS(alias))
  411. }
  412. // MATH method
  413. func (s *AlertQuerySelect) MATH(op string, val string) *AlertQuerySelect {
  414. return s.addPart(monitor.NewMetricQueryPartMath(op, val))
  415. }
  416. type AlertQueryWhere struct {
  417. parts []monitor.MetricQueryTag
  418. cond string
  419. }
  420. func (w *AlertQueryWhere) add(tags ...monitor.MetricQueryTag) *AlertQueryWhere {
  421. w.parts = append(w.parts, tags...)
  422. return w
  423. }
  424. func (w *AlertQueryWhere) condAdd(cond string, tags ...monitor.MetricQueryTag) *AlertQueryWhere {
  425. for i := range tags {
  426. tags[i].Condition = cond
  427. }
  428. w.add(tags...)
  429. return w
  430. }
  431. func (w *AlertQueryWhere) filter(op string, key string, value string) *AlertQueryWhere {
  432. if len(w.parts) == 0 {
  433. w.add(w.newTag(op, key, value))
  434. return w
  435. }
  436. return w.condAdd(w.cond, w.newTag(op, key, value))
  437. }
  438. func (w *AlertQueryWhere) Equal(key string, value string) *AlertQueryWhere {
  439. return w.filter("=", key, value)
  440. }
  441. func (w *AlertQueryWhere) NotEqual(key string, value string) *AlertQueryWhere {
  442. return w.filter("!=", key, value)
  443. }
  444. func (w *AlertQueryWhere) LT(key string, value string) *AlertQueryWhere {
  445. return w.filter("<", key, value)
  446. }
  447. func (w *AlertQueryWhere) GT(key string, value string) *AlertQueryWhere {
  448. return w.filter(">", key, value)
  449. }
  450. func (w *AlertQueryWhere) AND() *AlertQueryWhere {
  451. w.cond = "AND"
  452. return w
  453. }
  454. func (w *AlertQueryWhere) OR() *AlertQueryWhere {
  455. w.cond = "OR"
  456. return w
  457. }
  458. func (w *AlertQueryWhere) REGEX(key, val string) *AlertQueryWhere {
  459. return w.filter("=~", key, fmt.Sprintf("/%s/", val))
  460. }
  461. func (w *AlertQueryWhere) IN(key string, vals []string) *AlertQueryWhere {
  462. if len(vals) == 0 {
  463. return w
  464. }
  465. valStr := strings.Join(vals, "|")
  466. return w.REGEX(key, valStr)
  467. }
  468. func (w *AlertQueryWhere) AddTag(tag *monitor.MetricQueryTag) *AlertQueryWhere {
  469. if tag == nil {
  470. return w
  471. }
  472. if tag.Condition != "" {
  473. w.cond = tag.Condition
  474. }
  475. return w.filter(tag.Operator, tag.Key, tag.Value)
  476. }
  477. func (w *AlertQueryWhere) newTag(op string, key string, value string) monitor.MetricQueryTag {
  478. return monitor.MetricQueryTag{
  479. Key: key,
  480. Operator: op,
  481. Value: value,
  482. }
  483. }
  484. func (w *AlertQueryWhere) ToTags() []monitor.MetricQueryTag {
  485. return w.parts
  486. }
  487. type AlertQueryGroupBy struct {
  488. parts []monitor.MetricQueryPart
  489. }
  490. func (g *AlertQueryGroupBy) addPart(typ string, params ...string) *AlertQueryGroupBy {
  491. g.parts = append(g.parts, monitor.MetricQueryPart{
  492. Type: typ,
  493. Params: params,
  494. })
  495. return g
  496. }
  497. func (g *AlertQueryGroupBy) TIME(val string) *AlertQueryGroupBy {
  498. return g.addPart("time", val)
  499. }
  500. func (g *AlertQueryGroupBy) TAG(val string) *AlertQueryGroupBy {
  501. return g.addPart("tag", val)
  502. }
  503. func (g *AlertQueryGroupBy) FILL_NULL() *AlertQueryGroupBy {
  504. return g.FILL("null")
  505. }
  506. func (g *AlertQueryGroupBy) FILL(val string) *AlertQueryGroupBy {
  507. return g.addPart("fill", val)
  508. }
  509. func (g *AlertQueryGroupBy) ToGroupBy() []monitor.MetricQueryPart {
  510. return g.parts
  511. }
  512. type MetricQueryInput struct {
  513. from string `json:"from"`
  514. to string `json:"to"`
  515. scope string `json:"scope"`
  516. slimit string `json:"slimit"`
  517. soffset string `json:"soffset"`
  518. unit bool `json:"unit"`
  519. interval string `json:"interval"`
  520. domainId string `json:"domain_id"`
  521. projectId string `json:"project_id"`
  522. showMeta bool `json:"show_meta"`
  523. skipCheckSeries bool `json:"skip_check_series"`
  524. query *AlertQuery
  525. }
  526. func NewMetricQueryInput(measurement string) *MetricQueryInput {
  527. return NewMetricQueryInputWithDB("", measurement)
  528. }
  529. func NewMetricQueryInputWithDB(db string, measurement string) *MetricQueryInput {
  530. return &MetricQueryInput{
  531. query: NewAlertQuery(db, measurement),
  532. }
  533. }
  534. func (input *MetricQueryInput) Interval(interval string) *MetricQueryInput {
  535. input.interval = interval
  536. return input
  537. }
  538. func (input *MetricQueryInput) From(from time.Time) *MetricQueryInput {
  539. input.from = fmt.Sprintf("%d", from.UnixMilli())
  540. return input
  541. }
  542. func (input *MetricQueryInput) To(to time.Time) *MetricQueryInput {
  543. input.to = fmt.Sprintf("%d", to.UnixMilli())
  544. return input
  545. }
  546. func (input *MetricQueryInput) Scope(scope string) *MetricQueryInput {
  547. input.scope = scope
  548. return input
  549. }
  550. func (input *MetricQueryInput) SkipCheckSeries(skip bool) *MetricQueryInput {
  551. input.skipCheckSeries = skip
  552. return input
  553. }
  554. func (input *MetricQueryInput) Selects() *AlertQuerySelects {
  555. return input.query.Selects()
  556. }
  557. func (input *MetricQueryInput) Where() *AlertQueryWhere {
  558. return input.query.Where()
  559. }
  560. func (input *MetricQueryInput) GroupBy() *AlertQueryGroupBy {
  561. return input.query.GroupBy()
  562. }
  563. func (input *MetricQueryInput) Reducer(rType string, params []float64) *AlertQuery {
  564. return input.query.Reducer(rType, params)
  565. }
  566. func (input *MetricQueryInput) ToQueryData() *monitor.MetricQueryInput {
  567. data := &monitor.MetricQueryInput{
  568. From: input.from,
  569. To: input.to,
  570. Scope: input.scope,
  571. Slimit: input.slimit,
  572. Soffset: input.soffset,
  573. Unit: input.unit,
  574. Interval: input.interval,
  575. DomainId: input.domainId,
  576. ProjectId: input.projectId,
  577. ShowMeta: input.showMeta,
  578. SkipCheckSeries: input.skipCheckSeries,
  579. }
  580. data.MetricQuery = []*monitor.AlertQuery{
  581. {
  582. Model: input.query.ToMetricQuery(),
  583. ResultReducer: input.query.resultReducer,
  584. ResultReducerOrder: input.query.resultReducerOrder,
  585. },
  586. }
  587. jsonData := jsonutils.Marshal(data).(*jsonutils.JSONDict)
  588. digest := monitor.DigestQuerySignature(jsonData)
  589. data.Signature = digest
  590. return data
  591. }