smon/problem.go

199 lines
4.1 KiB
Go
Raw Permalink Normal View History

2024-04-29 08:36:13 +02:00
package main
import (
// External
werr "git.gibonuddevalla.se/go/wrappederror"
2024-04-29 08:36:13 +02:00
// Standard
"database/sql"
2024-05-01 20:01:43 +02:00
"encoding/json"
2024-07-04 08:54:03 +02:00
"fmt"
"sort"
"strings"
2024-05-01 20:01:43 +02:00
"time"
2024-04-29 08:36:13 +02:00
)
2024-07-04 08:54:03 +02:00
type Problem struct { // {{{
ID int
Start time.Time
2024-07-04 13:37:06 +02:00
End time.Time
2024-07-04 08:54:03 +02:00
Acknowledged bool
Datapoints map[string]any
DatapointValues map[string]any `json:"datapoints"`
TriggerID int `json:"trigger_id"`
TriggerName string `json:"trigger_name"`
AreaName string `json:"area_name"`
SectionName string `json:"section_name"`
} // }}}
2024-05-01 20:01:43 +02:00
2024-07-04 15:14:24 +02:00
func ProblemsRetrieve(showCurrent bool, from, to time.Time) (problems []Problem, err error) { // {{{
2024-05-01 20:01:43 +02:00
problems = []Problem{}
row := service.Db.Conn.QueryRow(`
SELECT
2024-05-28 07:23:27 +02:00
jsonb_agg(problems.*)
2024-05-01 20:01:43 +02:00
FROM (
2024-05-28 07:23:27 +02:00
(SELECT
2024-05-01 20:01:43 +02:00
p.id,
p.start,
2024-07-04 13:37:06 +02:00
TO_CHAR(p.end, 'YYYY-MM-DD"T"HH24:MI:SSTZH:TZM') AS end,
2024-05-01 20:01:43 +02:00
p.acknowledged,
2024-07-04 08:54:03 +02:00
p.datapoints,
2024-05-01 20:01:43 +02:00
t.id AS trigger_id,
2024-07-04 15:59:29 +02:00
p.trigger_name AS trigger_name,
2024-05-01 20:01:43 +02:00
a.name AS area_name,
s.name AS section_name
FROM problem p
2024-07-04 15:59:29 +02:00
LEFT JOIN "trigger" t ON p.trigger_id = t.id
LEFT JOIN section s ON t.section_id = s.id
LEFT JOIN area a ON s.area_id = a.id
2024-05-01 20:01:43 +02:00
WHERE
2024-07-04 13:37:06 +02:00
CASE
2024-07-04 15:14:24 +02:00
WHEN NOT $1 THEN p.end IS NULL
WHEN $1 THEN
p.start >= $2 AND
(
p.end IS NULL OR
p.end <= $3
)
END
2024-07-04 13:37:06 +02:00
2024-05-28 07:23:27 +02:00
ORDER BY
p.start DESC)
UNION ALL
2024-07-04 13:37:06 +02:00
2024-05-28 07:23:27 +02:00
(SELECT
-1 AS id,
2024-07-04 15:14:24 +02:00
dp.last_value,
2024-05-28 07:23:27 +02:00
null,
false,
2024-07-04 08:54:03 +02:00
'{}',
2024-05-28 07:23:27 +02:00
-1 AS trigger_id,
CONCAT(
'NODATA: ',
dp.name
) AS trigger_name,
'[NODATA]' AS area_name,
'[NODATA]' AS section_name
FROM datapoint dp
WHERE
dp.nodata_is_problem
ORDER BY
dp.name ASC)
2024-07-04 13:37:06 +02:00
) AS problems`,
2024-07-04 15:14:24 +02:00
showCurrent,
2024-07-04 13:37:06 +02:00
from,
to,
)
2024-05-01 20:01:43 +02:00
var jsonBody []byte
err = row.Scan(&jsonBody)
if err != nil {
err = werr.Wrap(err)
2024-05-01 20:01:43 +02:00
return
}
if jsonBody == nil {
return
}
2024-05-01 20:01:43 +02:00
err = json.Unmarshal(jsonBody, &problems)
if err != nil {
err = werr.Wrap(err)
2024-05-01 20:01:43 +02:00
}
return
2024-07-04 08:54:03 +02:00
} // }}}
func ProblemStart(trigger Trigger) (problemID int, err error) { // {{{
row := service.Db.Conn.QueryRow(`
SELECT COUNT(id)
FROM problem
WHERE
trigger_id = $1 AND
"end" IS NULL
GROUP BY trigger_id
`,
trigger.ID,
)
var openProblems int
err = row.Scan(&openProblems)
if err != nil && err != sql.ErrNoRows {
err = werr.Wrap(err).WithData(trigger.ID)
return
}
// Open up a new problem if no open exists.
if openProblems == 0 {
datapointValuesJson, _ := json.Marshal(trigger.DatapointValues)
2024-07-04 13:37:06 +02:00
row = service.Db.Conn.QueryRow(
2024-07-04 15:59:29 +02:00
`INSERT INTO problem(trigger_id, trigger_name, datapoints, trigger_expression) VALUES($1, $2, $3, $4) RETURNING id`,
2024-07-04 13:37:06 +02:00
trigger.ID,
2024-07-04 15:59:29 +02:00
trigger.Name,
2024-07-04 13:37:06 +02:00
datapointValuesJson,
trigger.Expression,
)
2024-05-05 20:16:28 +02:00
err = row.Scan(&problemID)
if err != nil {
err = werr.Wrap(err).WithData(trigger)
}
}
return
2024-07-04 08:54:03 +02:00
} // }}}
func ProblemClose(trigger Trigger) (problemID int, err error) { // {{{
2024-05-05 20:16:28 +02:00
row := service.Db.Conn.QueryRow(`UPDATE problem SET "end"=NOW() WHERE trigger_id=$1 AND "end" IS NULL RETURNING id`, trigger.ID)
err = row.Scan(&problemID)
if err == sql.ErrNoRows {
err = nil
return
}
if err != nil {
err = werr.Wrap(err).WithData(trigger)
return
}
return
2024-07-04 08:54:03 +02:00
} // }}}
func ProblemAcknowledge(id int, state bool) (err error) { // {{{
2024-05-01 20:01:43 +02:00
_, err = service.Db.Conn.Exec(`UPDATE problem SET "acknowledged"=$2 WHERE id=$1`, id, state)
if err != nil {
err = werr.Wrap(err).WithData(id)
2024-05-01 20:01:43 +02:00
return
}
return
2024-07-04 08:54:03 +02:00
} // }}}
2024-07-04 13:37:06 +02:00
func (p Problem) FormattedValues() string { // {{{
2024-07-04 08:54:03 +02:00
out := []string{}
for key, val := range p.DatapointValues {
2024-07-04 09:21:24 +02:00
var keyval string
switch val.(type) {
case int:
keyval = fmt.Sprintf("%s: %d", key, val)
case string:
if str, ok := val.(string); ok {
timeVal, err := time.Parse(time.RFC3339, str)
if err == nil {
formattedTime := timeVal.Format("2006-01-02 15:04:05")
keyval = fmt.Sprintf("%s: %s", key, formattedTime)
} else {
keyval = fmt.Sprintf("%s: %s", key, val)
}
}
default:
keyval = fmt.Sprintf("%s: %v", key, val)
2024-07-04 08:54:03 +02:00
}
2024-07-04 09:21:24 +02:00
out = append(out, keyval)
2024-07-04 08:54:03 +02:00
}
sort.Strings(out)
return strings.Join(out, "\n")
2024-07-04 13:37:06 +02:00
} // }}}
func (p Problem) IsArchived() bool { // {{{
return !p.End.IsZero()
} // }}}