diff --git a/main.go b/main.go index c0f557b..e40494a 100644 --- a/main.go +++ b/main.go @@ -205,7 +205,7 @@ func entryDatapoint(w http.ResponseWriter, r *http.Request, sess *session.T) { / logger.Error("entry", "error", err) } - // Multiple triggers can use the same datapoint. + // Multiple triggers can use the same datapoint. for _, trigger := range triggers { var out any out, err = trigger.Run() @@ -217,25 +217,25 @@ func entryDatapoint(w http.ResponseWriter, r *http.Request, sess *session.T) { / logger.Debug("entry", "datapoint", dpoint, "value", value, "trigger", trigger, "result", out) var problemID int + var problemState string switch v := out.(type) { case bool: // Trigger returning true - a problem occurred if v { problemID, err = ProblemStart(trigger) - logger.Info("FOO", "problemID", problemID, "err==nil", err == nil) if err != nil { err = werr.Wrap(err).Log() logger.Error("entry", "error", err) } - + problemState = "PROBLEM" } else { // A problem didn't occur. problemID, err = ProblemClose(trigger) - logger.Info("FOO", "problemID", problemID, "err==nil", err == nil) if err != nil { err = werr.Wrap(err).Log() logger.Error("entry", "error", err) } + problemState = "OK" } // Has a change in problem state happened? @@ -246,7 +246,7 @@ func entryDatapoint(w http.ResponseWriter, r *http.Request, sess *session.T) { / logger.Debug("notification", "trigger", trigger.ID, "state", "change") } - err = notificationManager.Send(problemID, []byte(trigger.Name), func(notificationService *notification.Service, err error) { + err = notificationManager.Send(problemID, []byte(problemState+": "+trigger.Name), func(notificationService *notification.Service, err error) { logger.Info( "notification", "service", (*notificationService).GetType(), @@ -617,12 +617,12 @@ func pageDatapointValues(w http.ResponseWriter, r *http.Request, _ *session.T) { PAGE: "datapoint_values", MENU: "datapoints", Icon: "datapoints", - Label: "Values for "+datapoint.Name, + Label: "Values for " + datapoint.Name, } page.Data = map[string]any{ "Datapoint": datapoint, - "Values": values, + "Values": values, } page.Render(w) return diff --git a/nodata.go b/nodata.go index b30a239..ba1e625 100644 --- a/nodata.go +++ b/nodata.go @@ -4,38 +4,95 @@ import ( // External werr "git.gibonuddevalla.se/go/wrappederror" + // Internal + "smon/notification" + // Standard "database/sql" + "encoding/json" "time" ) +var ( + nodataAreaID int + nodataSectionID int +) + // nodataLoop checks if datapoint last_value is larger than the nodata_problem_seconds period and // marks them as problems. They are then notified. func nodataLoop() { - var ids []int + var datapoints []Datapoint var err error // TODO - should be configurable ticker := time.NewTicker(time.Second * 5) for { <-ticker.C - ids, err = nodataDatapointIDs() + datapoints, err = nodataDatapoints() if err != nil { err = werr.Wrap(err).Log() logger.Error("nodata", "error", err) continue } - if len(ids) == 0 { + if len(datapoints) == 0 { continue } - logger.Info("nodata", "problem_ids", ids) + for _, datapoint := range datapoints { + nodataNotify(datapoint, "[NODATA] problem") + } + + logger.Info("nodata", "problem_ids", datapoints) } } -func nodataDatapointIDs() (ids []int, err error) { - ids = []int{} +func nodataNotify(datapoint Datapoint, state string) (err error) { + err = notificationManager.Send(-1, []byte(state+": "+datapoint.Name), func(notificationService *notification.Service, err error) { + logger.Info( + "notification", + "service", (*notificationService).GetType(), + "datapointID", datapoint.ID, + "prio", (*notificationService).GetPrio(), + "ok", true, + ) + + var errBody any + if err != nil { + errBody, _ = json.Marshal(err) + } else { + errBody = nil + } + _, err = service.Db.Conn.Exec( + ` + INSERT INTO notification_send(notification_id, datapoint_nodata_id, uuid, ok, error) + SELECT + id, $3, '', $4, $5 + FROM notification + WHERE + service=$1 AND + prio=$2 + `, + (*notificationService).GetType(), + (*notificationService).GetPrio(), + datapoint.ID, + err == nil, + errBody, + ) + if err != nil { + err = werr.Wrap(err).Log() + logger.Error("entry", "error", err) + } + }) + if err != nil { + err = werr.Wrap(err).Log() + logger.Error("notification", "error", err) + } + return +} + +func nodataDatapoints() (datapoints []Datapoint, err error) { + datapoints = []Datapoint{} var rows *sql.Rows rows, err = service.Db.Conn.Query(` @@ -54,7 +111,8 @@ func nodataDatapointIDs() (ids []int, err error) { WHERE datapoint.id = subquery.id RETURNING - datapoint.id + datapoint.id, + datapoint.name `) if err != nil { @@ -63,13 +121,13 @@ func nodataDatapointIDs() (ids []int, err error) { } defer rows.Close() - var id int + var dp Datapoint for rows.Next() { - if err = rows.Scan(&id); err != nil { + if err = rows.Scan(&dp.ID, &dp.Name); err != nil { err = werr.Wrap(err) return } - ids = append(ids, id) + datapoints = append(datapoints, dp) } return } diff --git a/sql/00015.sql b/sql/00015.sql new file mode 100644 index 0000000..0787d66 --- /dev/null +++ b/sql/00015.sql @@ -0,0 +1,3 @@ +ALTER TABLE public.notification_send ALTER COLUMN problem_id DROP NOT NULL; +ALTER TABLE public.notification_send ADD datapoint_nodata_id int4 NULL; +ALTER TABLE public.notification_send ADD CONSTRAINT notification_send_datapoint_fk FOREIGN KEY (datapoint_nodata_id) REFERENCES public.datapoint(id) ON DELETE CASCADE ON UPDATE CASCADE;