Skip to content

Commit 4e907f8

Browse files
cristianciuteafryckbos
authored andcommitted
Added dimensions specs for alert triggers (#15)
* Added dimensions specs for alert triggers
1 parent 66cf741 commit 4e907f8

File tree

2 files changed

+130
-21
lines changed

2 files changed

+130
-21
lines changed

src/coscale/api/alert.go

Lines changed: 101 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package api
22

33
import (
4+
"bytes"
45
"encoding/json"
56
"fmt"
7+
"strconv"
68
"strings"
79
)
810

@@ -46,17 +48,18 @@ func (a AlertType) GetId() int64 {
4648

4749
// AlertTrigger defines what Triggers an Alert of AlertType
4850
type AlertTrigger struct {
49-
ID int64
50-
Name string // Unique
51-
Description string
52-
AutoResolve int64 `json:"autoresolveSeconds"` // Optional
53-
Metric int64
54-
Config string
55-
OnApp bool
56-
GroupID int64 // Optional
57-
ServerID int64 // Optional
58-
Source string
59-
Version int64
51+
ID int64
52+
Name string // Unique
53+
Description string
54+
AutoResolve int64 `json:"autoresolveSeconds"` // Optional
55+
DimensionSpecs string // The dimension specs for the selected metric.
56+
Metric int64
57+
Config string
58+
OnApp bool
59+
GroupID int64 // Optional
60+
ServerID int64 // Optional
61+
Source string
62+
Version int64
6063
}
6164

6265
// GetId returns the id of the AlertTrigger.
@@ -161,7 +164,7 @@ func (api *Api) GetTriggers(alertTypeID int64) (string, error) {
161164
}
162165

163166
// CreateTrigger is used to add a new Trigger for alerts.
164-
func (api *Api) CreateTrigger(name, description, config string, alertTypeID, autoResolve, metricID, serverID, serverGroupID int64, onApp bool) (string, error) {
167+
func (api *Api) CreateTrigger(name, description, config, dimensionSpecs string, alertTypeID, autoResolve, metricID, serverID, serverGroupID int64, onApp bool) (string, error) {
165168

166169
data := map[string][]string{
167170
"name": {name},
@@ -172,6 +175,13 @@ func (api *Api) CreateTrigger(name, description, config string, alertTypeID, aut
172175
"source": {GetSource()},
173176
}
174177

178+
parsedDimensionSpecs, err := ParseDimensionSpecs(dimensionSpecs)
179+
if err != nil {
180+
return "", err
181+
}
182+
183+
data["dimensionSpecs"] = []string{parsedDimensionSpecs}
184+
175185
// Set the option values if they have value.
176186
if serverID != -1 {
177187
data["server"] = []string{fmt.Sprintf("%d", serverID)}
@@ -196,12 +206,13 @@ func (api *Api) CreateTrigger(name, description, config string, alertTypeID, aut
196206
func (api *Api) UpdateTrigger(typeID int64, trigger *AlertTrigger) (string, error) {
197207

198208
data := map[string][]string{
199-
"name": {trigger.Name},
200-
"description": {trigger.Description},
201-
"config": {trigger.Config},
202-
"onApp": {fmt.Sprintf("%t", trigger.OnApp)},
203-
"source": {trigger.Source},
204-
"version": {fmt.Sprintf("%d", trigger.Version)},
209+
"name": {trigger.Name},
210+
"description": {trigger.Description},
211+
"dimensionSpecs": {trigger.DimensionSpecs},
212+
"config": {trigger.Config},
213+
"onApp": {fmt.Sprintf("%t", trigger.OnApp)},
214+
"source": {trigger.Source},
215+
"version": {fmt.Sprintf("%d", trigger.Version)},
205216
}
206217

207218
// Set the option values if they have value.
@@ -267,3 +278,75 @@ func ParseHandle(handle string) (string, error) {
267278
jsonHandle, err := json.Marshal(result)
268279
return string(jsonHandle), err
269280
}
281+
282+
// ParseDimensionSpecs is used to parse the dimensions specs for a metric.
283+
func ParseDimensionSpecs(format string) (string, error) {
284+
var js interface{}
285+
// Check if the specs are already provided in JSON format.
286+
if err := json.Unmarshal([]byte(format), &js); err == nil {
287+
return format, nil
288+
}
289+
var buffer bytes.Buffer
290+
291+
formatParts := strings.Split(format, ";")
292+
293+
buffer.WriteString("[")
294+
for i, formatPart := range formatParts {
295+
if i > 0 {
296+
buffer.WriteString(",")
297+
}
298+
buffer.WriteString("[")
299+
300+
elements := strings.Split(formatPart, ":")
301+
302+
var dimPart, dimValsPart, aggregatorPart string
303+
if len(elements) == 2 {
304+
dimPart = elements[0]
305+
dimValsPart = elements[1]
306+
} else if len(elements) == 3 {
307+
dimPart = elements[0]
308+
aggregatorPart = strings.ToUpper(elements[1])
309+
dimValsPart = elements[2]
310+
} else {
311+
return "", fmt.Errorf("Failed to parse dimension specs format: %s", formatPart)
312+
}
313+
314+
if len(dimPart) == 0 || len(dimValsPart) == 0 {
315+
return "", fmt.Errorf("Failed to parse dimension specs format: %s", formatPart)
316+
}
317+
318+
dimID, err := strconv.ParseInt(dimPart, 10, 64)
319+
if err != nil {
320+
return "", fmt.Errorf("Failed to parse dimension specs format: %s", formatPart)
321+
}
322+
buffer.WriteString(fmt.Sprintf(`%d,"`, dimID))
323+
324+
// Just check if is valid format.
325+
if dimValsPart != "*" {
326+
for _, dimVal := range strings.Split(dimValsPart, ",") {
327+
_, err := strconv.ParseInt(dimVal, 10, 64)
328+
if err != nil {
329+
return "", fmt.Errorf("Failed to parse dimension values ids: %s", formatPart)
330+
}
331+
}
332+
}
333+
334+
if len(aggregatorPart) > 0 {
335+
buffer.WriteString(aggregatorPart)
336+
buffer.WriteString("(")
337+
buffer.WriteString(dimValsPart)
338+
buffer.WriteString(")")
339+
} else {
340+
buffer.WriteString(dimValsPart)
341+
}
342+
buffer.WriteString(`"]`)
343+
}
344+
buffer.WriteString("]")
345+
346+
// Check the format is valid.
347+
if err := json.Unmarshal([]byte(buffer.Bytes()), &js); err != nil {
348+
return "", err
349+
}
350+
351+
return buffer.String(), nil
352+
}

src/coscale/command/alert.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,15 @@ Optional:
412412
--servergroupid
413413
The servergroup id for which the alert will be triggered.
414414
Note: if no server or servergroup is provided the trigger will be set for the entire application.
415+
--dimensionsSpecs
416+
The dimensions specifications for the metric monitored in the following format:
417+
[[<dimension_id1>,"[agregator]<dimension_value_id1,dimension_value_id2...>",...]]
418+
e.g.: --dimensionsSpecs='[[1,"AVG(*)"]]'
419+
--dimensionsSpecs='[[2,"*"]]'
420+
--dimensionsSpecs='[[3,"11,12,13"],[4,"21,22,23"]]'
415421
`,
416422
Run: func(cmd *Command, args []string) {
417-
var name, config, metric, description, server, serverGroup, source, typeName string
423+
var name, config, metric, description, server, serverGroup, source, typeName, dimSpecs string
418424
var metricID, autoResolve, serverID, serverGroupID, typeID int64
419425
var onApp bool
420426

@@ -432,6 +438,7 @@ Optional:
432438
cmd.Flag.StringVar(&source, "source", "cli", "Deprecated.")
433439
cmd.Flag.StringVar(&typeName, "typename", "Default alerts", "Specify the name of the alert type for triggers.")
434440
cmd.Flag.Int64Var(&typeID, "typeid", -1, "Specify the alert type id for triggers.")
441+
cmd.Flag.StringVar(&dimSpecs, "dimensionsSpecs", "[]", "The dimensions specifications.")
435442

436443
cmd.ParseArgs(args)
437444

@@ -493,7 +500,7 @@ Optional:
493500
typeID = alertTypeObj.ID
494501
}
495502

496-
cmd.PrintResult(cmd.Capi.CreateTrigger(name, description, config, typeID, autoResolve, metricID, serverID, serverGroupID, onApp))
503+
cmd.PrintResult(cmd.Capi.CreateTrigger(name, description, config, dimSpecs, typeID, autoResolve, metricID, serverID, serverGroupID, onApp))
497504
},
498505
},
499506
{
@@ -541,9 +548,15 @@ Optional:
541548
--servergroupid
542549
The servergroup id for which the alert will be triggered.
543550
Note: if no server or servergroup is provided the tigger will be set for entire application.
551+
--dimensionsSpecs
552+
The dimensions specifications for the metric monitored in the following format:
553+
[[<dimension_id1>,"[agregator]<dimension_value_id1,dimension_value_id2...>",...]]
554+
e.g.: --dimensionsSpecs='[[1,"AVG(*)"]]'
555+
--dimensionsSpecs='[[2,"*"]]'
556+
--dimensionsSpecs='[[3,"11,12,13"],[4,"21,22,23"]]'
544557
`,
545558
Run: func(cmd *Command, args []string) {
546-
var name, config, metric, description, server, serverGroup, source, typeName string
559+
var name, config, metric, description, server, serverGroup, source, typeName, dimSpecs string
547560
var id, autoResolve, metricID, serverID, serverGroupID, typeID int64
548561
var onApp bool
549562

@@ -562,6 +575,7 @@ Optional:
562575
cmd.Flag.StringVar(&source, "source", DEFAULT_STRING_FLAG_VALUE, "Deprecated.")
563576
cmd.Flag.StringVar(&typeName, "typename", DEFAULT_STRING_FLAG_VALUE, "Specify the name of the alert type for triggers.")
564577
cmd.Flag.Int64Var(&typeID, "typeid", -1, "Specify the alert type id for triggers.")
578+
cmd.Flag.StringVar(&dimSpecs, "dimensionsSpecs", DEFAULT_STRING_FLAG_VALUE, "The dimensions specifications.")
565579

566580
cmd.ParseArgs(args)
567581

@@ -666,6 +680,18 @@ Optional:
666680
alertTriggerObj.OnApp = onApp
667681
}
668682

683+
if dimSpecs != DEFAULT_STRING_FLAG_VALUE {
684+
// Validate the dimensions specifications.
685+
parsedDimensionSpecs, err := api.ParseDimensionSpecs(dimSpecs)
686+
if err != nil {
687+
cmd.PrintResult("", err)
688+
}
689+
690+
if alertTriggerObj.DimensionSpecs != parsedDimensionSpecs {
691+
alertTriggerObj.DimensionSpecs = parsedDimensionSpecs
692+
}
693+
}
694+
669695
cmd.PrintResult(cmd.Capi.UpdateTrigger(typeID, alertTriggerObj))
670696
},
671697
},

0 commit comments

Comments
 (0)