Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add alert metadata #3764

Merged
merged 49 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
5f1d9af
alert metadata WIP
Forfold Mar 11, 2024
da7e2c9
add alert metada changes
shivanishendge Mar 21, 2024
e6e48ea
add alert type
shivanishendge Mar 21, 2024
d1deb73
add validation
shivanishendge Mar 21, 2024
3ca69c1
generic api handler correction
shivanishendge Mar 21, 2024
f772f32
add meta field to webhook notification
shivanishendge Mar 21, 2024
19a49d6
remove log statements
shivanishendge Mar 21, 2024
e25626c
resolve go lint issues
shivanishendge Mar 21, 2024
acc9b12
Update migrate/migrations/20240212125328-alert-metadata.sql
shivanishendge Mar 26, 2024
53e8839
Update graphql2/schema.graphql
shivanishendge Mar 26, 2024
c6026b0
Update graphql2/graphqlapp/alert.go
shivanishendge Mar 26, 2024
2ed2bd6
change as per review
shivanishendge Mar 26, 2024
1eea8c2
Add createMetaTx method
mastercactapus Mar 26, 2024
cd9d54b
fix urlform values
shivanishendge Mar 26, 2024
88decb8
fix generic api tests
shivanishendge Mar 26, 2024
ab33b35
Merge branch 'master' into add-alertMetadata
shivanishendge Mar 26, 2024
a9a00a6
fix lint error
shivanishendge Mar 26, 2024
2ee7763
remove commented code
mastercactapus Mar 26, 2024
6b4641d
move metadata out of CreateOrUpdate
mastercactapus Mar 26, 2024
3a46df7
update SetMetadata to support service permissions validation
mastercactapus Mar 26, 2024
3ed9354
fix type for manymetadata and add single query
mastercactapus Mar 26, 2024
63bb1d7
regen sqlc
mastercactapus Mar 26, 2024
f0191dc
move store methods to metadata.go
mastercactapus Mar 26, 2024
166a01e
move validation to metadata.go
mastercactapus Mar 26, 2024
f4bb587
missing sig. updates
mastercactapus Mar 26, 2024
aef1cc3
add ServiceNullUUID method to permission pkg
mastercactapus Mar 26, 2024
bd84139
update grafana call
mastercactapus Mar 26, 2024
9d6e758
regen sqlc
mastercactapus Mar 26, 2024
5511efb
fix CreateOrUpdate call
mastercactapus Mar 26, 2024
230510d
add db in call for metadata
mastercactapus Mar 26, 2024
303ceed
fix edge case handling in MetaValue
mastercactapus Mar 26, 2024
57d1371
move map handling out of Tx function
mastercactapus Mar 26, 2024
e628cd5
add create CreateOrUpdateWithMeta store method and update generic api…
shivanishendge Mar 28, 2024
56de5ce
add comment
shivanishendge Mar 28, 2024
d5add2f
Merge branch 'master' into add-alertMetadata
mastercactapus Apr 1, 2024
8f3d384
remove unused queries
mastercactapus Apr 1, 2024
40f8f29
clairify comment
mastercactapus Apr 1, 2024
26e067e
tweak error message
mastercactapus Apr 1, 2024
1effb27
cleanup graphql code
mastercactapus Apr 1, 2024
36e627d
update documentation
mastercactapus Apr 1, 2024
3a05169
remove changes to existing tests (will create new)
mastercactapus Apr 1, 2024
610dc1e
add metadata smoke test
mastercactapus Apr 1, 2024
c3f57d9
add dataloader for batching metadata lookups
mastercactapus Apr 1, 2024
940b669
use dataloader
mastercactapus Apr 1, 2024
aeb3444
Merge remote-tracking branch 'origin/master' into add-alertMetadata
mastercactapus Apr 1, 2024
37c716e
regen
mastercactapus Apr 1, 2024
695fa9f
add id column for switchover
mastercactapus Apr 1, 2024
c400820
Merge branch 'master' into add-alertMetadata
mastercactapus Apr 2, 2024
6fe5702
regen sqlc
mastercactapus Apr 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions alert/alert.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"
"time"

"github.com/target/goalert/validation"
"github.com/target/goalert/validation/validate"
)

Expand All @@ -25,6 +26,7 @@ type Alert struct {
ServiceID string `json:"service_id"`
CreatedAt time.Time `json:"created_at"`
Dedup *DedupID `json:"dedup"`
Meta AlertMeta `json:"meta"`
mastercactapus marked this conversation as resolved.
Show resolved Hide resolved
}

// DedupKey will return the de-duplication key for the alert.
Expand Down Expand Up @@ -57,12 +59,21 @@ func (a Alert) Normalize() (*Alert, error) {
}
a.Summary = strings.Replace(a.Summary, "\n", " ", -1)
a.Summary = strings.Replace(a.Summary, " ", " ", -1)

var validateMeta error
for k := range a.Meta.AlertMetaV1 {
if k == "" {
validateMeta = validation.NewFieldError("Meta", "key must be non empty string")
}
}
mastercactapus marked this conversation as resolved.
Show resolved Hide resolved

err := validate.Many(
validate.Text("Summary", a.Summary, 1, MaxSummaryLength),
validate.Text("Details", a.Details, 0, MaxDetailsLength),
validate.OneOf("Source", a.Source, SourceManual, SourceGrafana, SourceSite24x7, SourcePrometheusAlertmanager, SourceEmail, SourceGeneric),
validate.OneOf("Status", a.Status, StatusTriggered, StatusActive, StatusClosed),
validate.UUID("ServiceID", a.ServiceID),
validateMeta,
)
if err != nil {
return nil, err
Expand Down
26 changes: 26 additions & 0 deletions alert/meta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package alert

const TypeAlertMetaV1 = "alert_meta_v1"

type AlertMeta struct {
Type string `json:"type"`
AlertMetaV1 AlertMetaData `json:"alert_meta_v1"`
}
Forfold marked this conversation as resolved.
Show resolved Hide resolved

type AlertMetaData map[string]string
mastercactapus marked this conversation as resolved.
Show resolved Hide resolved

type AlertMetaInput []struct {
Key string `json:"key"`
Value string `json:"value"`
}

func ToAlertMeta(meta AlertMetaInput) AlertMeta {
alertMeta := AlertMetaData{}
for _, v := range meta {
alertMeta[v.Key] = v.Value
}
return AlertMeta{
Type: TypeAlertMetaV1,
AlertMetaV1: alertMeta,
}
}
mastercactapus marked this conversation as resolved.
Show resolved Hide resolved
35 changes: 35 additions & 0 deletions alert/queries.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ WHERE
alerts.id = $1
FOR UPDATE;

-- name: Insert :one
INSERT INTO alerts(summary, details, service_id, source, status, dedup_key)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING
id, created_at;

-- name: NoStepsByService :one
SELECT
COALESCE((
SELECT
TRUE
FROM escalation_policies pol
JOIN services svc ON svc.id = $1
WHERE
pol.id = svc.escalation_policy_id
AND pol.step_count = 0), FALSE) AS no_steps_by_service;

-- name: RequestAlertEscalationByTime :one
UPDATE
escalation_policy_state
Expand Down Expand Up @@ -60,3 +77,21 @@ ON CONFLICT (alert_id)
RETURNING
alert_id;

-- name: AlertMetadataMany :many
SELECT
alert_id,
metadata
FROM
alerts_metadata
WHERE
alert_id = ANY ($1::int[]);

-- name: SetAlertMetadata :exec
INSERT INTO alerts_metadata(alert_id, metadata)
VALUES ($1, $2)
ON CONFLICT (alert_id)
DO UPDATE SET
metadata = $2
WHERE
alerts_metadata.alert_id = $1;

87 changes: 87 additions & 0 deletions alert/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package alert
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"time"

"github.com/sqlc-dev/pqtype"
"github.com/target/goalert/alert/alertlog"
"github.com/target/goalert/gadb"
"github.com/target/goalert/permission"
Expand Down Expand Up @@ -527,6 +529,14 @@ func (s *Store) _create(ctx context.Context, tx *sql.Tx, a Alert) (*Alert, *aler
return nil, nil, err
}

// insert alert metadata
err = s.insertMetaData(tx, ctx, a.ID, a.Meta.AlertMetaV1)
if err != nil {
return nil, nil, err
}

ctx = log.WithFields(ctx, log.Fields{"AlertID": a.ID, "Meta": a.Meta.AlertMetaV1})
log.Logf(ctx, "Alert created.")
mastercactapus marked this conversation as resolved.
Show resolved Hide resolved
err = tx.StmtContext(ctx, s.noStepsBySvc).QueryRowContext(ctx, a.ServiceID).Scan(&meta.EPNoSteps)
if err != nil {
return nil, nil, err
Expand Down Expand Up @@ -585,6 +595,11 @@ func (s *Store) CreateOrUpdateTx(ctx context.Context, tx *sql.Tx, a *Alert) (*Al
if stepErr != nil {
return nil, false, err
}
// insert alert metadata
err = s.insertMetaData(tx, ctx, n.ID, a.Meta.AlertMetaV1)
if err != nil {
return nil, false, err
}
}
meta = &m
case StatusActive:
Expand Down Expand Up @@ -741,6 +756,8 @@ func (s *Store) FindMany(ctx context.Context, alertIDs []int) ([]Alert, error) {
}
defer rows.Close()

amd, _ := s.MetadataMany(ctx, alertIDs)

alerts := make([]Alert, 0, len(alertIDs))

for rows.Next() {
Expand All @@ -749,6 +766,11 @@ func (s *Store) FindMany(ctx context.Context, alertIDs []int) ([]Alert, error) {
if err != nil {
return nil, err
}
if val, ok := amd[int32(a.ID)]; ok {
a.Meta = AlertMeta{
AlertMetaV1: val,
}
}
alerts = append(alerts, a)
}

Expand Down Expand Up @@ -881,3 +903,68 @@ func (s Store) UpdateFeedback(ctx context.Context, feedback *Feedback) error {

return nil
}

func (s Store) Metadata(ctx context.Context, alertID int) (AlertMetaData, error) {
err := permission.LimitCheckAny(ctx, permission.System, permission.User)
if err != nil {
return nil, err
}
md, err := s.MetadataMany(ctx, []int{alertID})
if err != nil {
return nil, err
}
if amd, ok := md[int32(alertID)]; ok {
return amd, nil
}
return nil, validation.NewFieldError("ID", "not found")
}

func (s Store) MetadataMany(ctx context.Context, alertIDs []int) (map[int32]AlertMetaData, error) {
err := permission.LimitCheckAny(ctx, permission.System, permission.User)
if err != nil {
return nil, err
}

err = validate.Range("AlertIDs", len(alertIDs), 1, maxBatch)
if err != nil {
return nil, err
}
ids := make([]int32, len(alertIDs))
for _, id := range alertIDs {
ids = append(ids, int32(id))
}

amd := map[int32]AlertMetaData{}
rows, err := gadb.New(s.db).AlertMetadataMany(ctx, ids)
if errors.Is(err, sql.ErrNoRows) {
return amd, err
}
if err != nil {
return amd, err
}

for _, r := range rows {
if r.Metadata.Valid {
var md AlertMetaData
err = json.Unmarshal(r.Metadata.RawMessage, &md)
if err == nil {
amd[r.AlertID] = md
} else {
amd[r.AlertID] = nil
}
}
}
return amd, err
}

func (s Store) insertMetaData(tx *sql.Tx, ctx context.Context, alertID int, metaData AlertMetaData) error {
meta, err := json.Marshal(&metaData)
if err != nil {
return err
}
err = gadb.New(tx).SetAlertMetadata(ctx, gadb.SetAlertMetadataParams{
AlertID: int32(alertID),
Metadata: pqtype.NullRawMessage{Valid: metaData != nil, RawMessage: json.RawMessage(meta)},
})
return err
}
7 changes: 7 additions & 0 deletions engine/sendmessage.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ func (p *Engine) sendMessage(ctx context.Context, msg *message.Message) (*notifi
// set to nil if it's the current message
stat = nil
}
var meta []notification.AlertMeta
if a.Meta.AlertMetaV1 != nil {
for k, v := range a.Meta.AlertMetaV1 {
meta = append(meta, notification.AlertMeta{Key: k, Value: v})
}
}
notifMsg = notification.Alert{
Dest: msg.Dest,
AlertID: msg.AlertID,
Expand All @@ -79,6 +85,7 @@ func (p *Engine) sendMessage(ctx context.Context, msg *message.Message) (*notifi
CallbackID: msg.ID,
ServiceID: a.ServiceID,
ServiceName: name,
Meta: meta,

OriginalStatus: stat,
}
Expand Down
6 changes: 6 additions & 0 deletions gadb/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading