/compass/internal/metricsgroup/metricsgroup.go

https://github.com/ZupIT/charlescd · Go · 333 lines · 258 code · 58 blank · 17 comment · 69 complexity · 9ae8ad4c8479d27ca8a62e8a75b6ca33 MD5 · raw file

  1. /*
  2. *
  3. * Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package metricsgroup
  19. import (
  20. "compass/internal/metric"
  21. "compass/internal/util"
  22. "compass/pkg/datasource"
  23. "compass/pkg/logger"
  24. "encoding/json"
  25. "errors"
  26. "io"
  27. "regexp"
  28. "sort"
  29. "github.com/google/uuid"
  30. "github.com/jinzhu/gorm"
  31. )
  32. type MetricsGroup struct {
  33. util.BaseModel
  34. Name string `json:"name"`
  35. Metrics []metric.Metric `json:"metrics"`
  36. WorkspaceID uuid.UUID `json:"-"`
  37. CircleID uuid.UUID `json:"circleId"`
  38. }
  39. type MetricGroupResume struct {
  40. util.BaseModel
  41. Name string `json:"name"`
  42. Thresholds int `json:"thresholds"`
  43. ThresholdsReached int `json:"thresholdsReached"`
  44. Metrics int `json:"metricsCount"`
  45. Status string `json:"status"`
  46. }
  47. func (main Main) Validate(metricsGroup MetricsGroup) []util.ErrorUtil {
  48. ers := make([]util.ErrorUtil, 0)
  49. if metricsGroup.Name == "" {
  50. ers = append(ers, util.ErrorUtil{Field: "name", Error: errors.New("Name is required").Error()})
  51. }
  52. if metricsGroup.CircleID == uuid.Nil {
  53. ers = append(ers, util.ErrorUtil{Field: "circleID", Error: errors.New("CircleID is required").Error()})
  54. }
  55. if metricsGroup.Name != "" && len(metricsGroup.Name) > 100 {
  56. ers = append(ers, util.ErrorUtil{Field: "name", Error: errors.New("100 Maximum length in Name").Error()})
  57. }
  58. return ers
  59. }
  60. type Condition int
  61. const (
  62. EQUAL Condition = iota
  63. GREATER_THAN
  64. LOWER_THAN
  65. )
  66. var Periods = map[string]string{
  67. "s": "s",
  68. "m": "m",
  69. "h": "h",
  70. "d": "d",
  71. "w": "w",
  72. "y": "y",
  73. "MAX": "MAX",
  74. }
  75. func (c Condition) String() string {
  76. return [...]string{"EQUAL", "GREATER_THAN", "LOWER_THAN"}[c]
  77. }
  78. func (main Main) PeriodValidate(currentPeriod string) error {
  79. reg, err := regexp.Compile("[0-9]")
  80. if err != nil {
  81. logger.Error(util.PeriodValidateRegexError, "PeriodValidate", err, currentPeriod)
  82. return errors.New("Invalid period or interval")
  83. }
  84. if currentPeriod != "" && !reg.Match([]byte(currentPeriod)) {
  85. logger.Error(util.PeriodValidateError, "PeriodValidate", err, currentPeriod)
  86. return errors.New("Invalid period or interval: not found number")
  87. }
  88. unit := reg.ReplaceAllString(currentPeriod, "")
  89. _, ok := Periods[unit]
  90. if !ok && currentPeriod != "" {
  91. logger.Error(util.PeriodValidateError, "PeriodValidate", err, currentPeriod)
  92. return errors.New("Invalid period or interval: not found unit")
  93. }
  94. return nil
  95. }
  96. func (main Main) Parse(metricsGroup io.ReadCloser) (MetricsGroup, error) {
  97. var newMetricsGroup *MetricsGroup
  98. err := json.NewDecoder(metricsGroup).Decode(&newMetricsGroup)
  99. if err != nil {
  100. logger.Error(util.GeneralParseError, "Parse", err, metricsGroup)
  101. return MetricsGroup{}, err
  102. }
  103. return *newMetricsGroup, nil
  104. }
  105. func (main Main) FindAll() ([]MetricsGroup, error) {
  106. var metricsGroups []MetricsGroup
  107. db := main.db.Set("gorm:auto_preload", true).Find(&metricsGroups)
  108. if db.Error != nil {
  109. logger.Error(util.FindMetricsGroupError, "FindAll", db.Error, metricsGroups)
  110. return []MetricsGroup{}, db.Error
  111. }
  112. return metricsGroups, nil
  113. }
  114. func (main Main) isMetricError(metrics []metric.Metric) bool {
  115. for _, currentMetric := range metrics {
  116. if currentMetric.MetricExecution.Status == metric.MetricError {
  117. return true
  118. }
  119. }
  120. return false
  121. }
  122. func (main Main) getResumeStatusByGroup(reachedMetrics, configuredMetrics int, metrics []metric.Metric) string {
  123. if main.isMetricError(metrics) {
  124. return metric.MetricError
  125. }
  126. if reachedMetrics == configuredMetrics && reachedMetrics > 0 {
  127. return metric.MetricReached
  128. }
  129. return metric.MetricActive
  130. }
  131. func (main Main) ResumeByCircle(circleId string) ([]MetricGroupResume, error) {
  132. var db *gorm.DB
  133. var metricsGroups []MetricsGroup
  134. var metricsGroupsResume []MetricGroupResume
  135. if circleId == "" {
  136. db = main.db.Set("gorm:auto_preload", true).Find(&metricsGroups)
  137. } else {
  138. circleIdParsed, _ := uuid.Parse(circleId)
  139. db = main.db.Set("gorm:auto_preload", true).Where("circle_id=?", circleIdParsed).Find(&metricsGroups)
  140. }
  141. if db.Error != nil {
  142. logger.Error(util.ResumeByCircleError, "ResumeByCircle", db.Error, metricsGroups)
  143. return []MetricGroupResume{}, db.Error
  144. }
  145. for _, group := range metricsGroups {
  146. configuredMetrics, reachedMetrics, allMetrics := main.metricMain.CountMetrics(group.Metrics)
  147. metricsGroupsResume = append(metricsGroupsResume, MetricGroupResume{
  148. group.BaseModel,
  149. group.Name,
  150. configuredMetrics,
  151. reachedMetrics,
  152. allMetrics,
  153. main.getResumeStatusByGroup(reachedMetrics, configuredMetrics, group.Metrics),
  154. })
  155. }
  156. main.sortResumeMetrics(metricsGroupsResume)
  157. return metricsGroupsResume, nil
  158. }
  159. func (main Main) sortResumeMetrics(metricsGroupResume []MetricGroupResume) {
  160. sort.SliceStable(metricsGroupResume, func(i, j int) bool {
  161. if (metricsGroupResume[i].ThresholdsReached == metricsGroupResume[i].Thresholds) &&
  162. (metricsGroupResume[j].ThresholdsReached == metricsGroupResume[j].Thresholds) &&
  163. (metricsGroupResume[i].ThresholdsReached > metricsGroupResume[j].ThresholdsReached) {
  164. return true
  165. }
  166. if metricsGroupResume[i].Thresholds == 0 {
  167. return false
  168. }
  169. if metricsGroupResume[j].Thresholds == 0 {
  170. return true
  171. }
  172. if metricsGroupResume[i].ThresholdsReached == metricsGroupResume[i].Thresholds {
  173. return true
  174. }
  175. if metricsGroupResume[j].ThresholdsReached == metricsGroupResume[j].Thresholds {
  176. return false
  177. }
  178. if metricsGroupResume[i].ThresholdsReached == 0 && metricsGroupResume[j].ThresholdsReached == 0 {
  179. return metricsGroupResume[i].Thresholds > metricsGroupResume[j].Thresholds
  180. }
  181. return metricsGroupResume[i].ThresholdsReached > metricsGroupResume[j].ThresholdsReached
  182. })
  183. }
  184. func (main Main) Save(metricsGroup MetricsGroup) (MetricsGroup, error) {
  185. db := main.db.Create(&metricsGroup)
  186. if db.Error != nil {
  187. logger.Error(util.SaveMetricsGroupError, "Save", db.Error, metricsGroup)
  188. return MetricsGroup{}, db.Error
  189. }
  190. return metricsGroup, nil
  191. }
  192. func (main Main) FindById(id string) (MetricsGroup, error) {
  193. metricsGroup := MetricsGroup{}
  194. db := main.db.Set("gorm:auto_preload", true).Where("id = ?", id).First(&metricsGroup)
  195. if db.Error != nil {
  196. logger.Error(util.FindMetricsGroupError, "FindById", db.Error, "Id = "+id)
  197. return MetricsGroup{}, db.Error
  198. }
  199. return metricsGroup, nil
  200. }
  201. func (main Main) FindCircleMetricGroups(circleId string) ([]MetricsGroup, error) {
  202. var metricsGroups []MetricsGroup
  203. db := main.db.Set("gorm:auto_preload", true).Where("circle_id = ?", circleId).Find(&metricsGroups)
  204. if db.Error != nil {
  205. logger.Error(util.FindMetricsGroupError, "FindCircleMetricGroups", db.Error, "CircleId= "+circleId)
  206. return []MetricsGroup{}, db.Error
  207. }
  208. return metricsGroups, nil
  209. }
  210. func (main Main) Update(id string, metricsGroup MetricsGroup) (MetricsGroup, error) {
  211. db := main.db.Table("metrics_groups").Where("id = ?", id).Update(&metricsGroup)
  212. if db.Error != nil {
  213. logger.Error(util.UpdateMetricsGroupError, "Update", db.Error, metricsGroup)
  214. return MetricsGroup{}, db.Error
  215. }
  216. return metricsGroup, nil
  217. }
  218. func (main Main) Remove(id string) error {
  219. db := main.db.Where("id = ?", id).Delete(MetricsGroup{})
  220. if db.Error != nil {
  221. logger.Error(util.RemoveMetricsGroupError, "Remove", db.Error, id)
  222. return db.Error
  223. }
  224. return nil
  225. }
  226. func (main Main) QueryByGroupID(id, period, interval string) ([]datasource.MetricValues, error) {
  227. var metricsValues []datasource.MetricValues
  228. metricsGroup, err := main.FindById(id)
  229. if err != nil {
  230. notFoundErr := errors.New("Not found metrics group: " + id)
  231. logger.Error(util.FindMetricsGroupError, "QueryByGroupID", notFoundErr, id)
  232. return []datasource.MetricValues{}, notFoundErr
  233. }
  234. if len(metricsGroup.Metrics) == 0 {
  235. return []datasource.MetricValues{}, nil
  236. }
  237. for _, metric := range metricsGroup.Metrics {
  238. query, err := main.metricMain.Query(metric, period, interval)
  239. if err != nil {
  240. logger.Error(util.QueryByGroupIdError, "QueryByGroupID", err, metric)
  241. return []datasource.MetricValues{}, err
  242. }
  243. metricsValues = append(metricsValues, datasource.MetricValues{
  244. ID: metric.ID,
  245. Nickname: metric.Nickname,
  246. Values: query,
  247. })
  248. }
  249. return metricsValues, nil
  250. }
  251. func (main Main) ResultByGroup(group MetricsGroup) ([]datasource.MetricResult, error) {
  252. var metricsResults []datasource.MetricResult
  253. for _, metric := range group.Metrics {
  254. result, err := main.metricMain.ResultQuery(metric)
  255. if err != nil {
  256. logger.Error(util.ResultQueryError, "ResultByGroup", err, metric)
  257. return nil, err
  258. }
  259. metricsResults = append(metricsResults, datasource.MetricResult{
  260. ID: metric.ID,
  261. Nickname: metric.Nickname,
  262. Result: result,
  263. })
  264. }
  265. return metricsResults, nil
  266. }
  267. func (main Main) ResultByID(id string) ([]datasource.MetricResult, error) {
  268. metricsGroup, err := main.FindById(id)
  269. if err != nil {
  270. notFoundErr := errors.New("Not found metrics group: " + id)
  271. logger.Error(util.FindMetricsGroupError, "ResultByID", notFoundErr, id)
  272. return []datasource.MetricResult{}, notFoundErr
  273. }
  274. return main.ResultByGroup(metricsGroup)
  275. }