store creation and resolve times in alert
This commit is contained in:
parent
3314ffe833
commit
330bb05f9f
|
@ -75,6 +75,7 @@ func (api *API) addAlerts(w http.ResponseWriter, r *http.Request) {
|
||||||
for _, alert := range alerts {
|
for _, alert := range alerts {
|
||||||
if alert.Timestamp.IsZero() {
|
if alert.Timestamp.IsZero() {
|
||||||
alert.Timestamp = time.Now()
|
alert.Timestamp = time.Now()
|
||||||
|
alert.CreatedAt = alert.Timestamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package manager
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -26,7 +27,10 @@ func NewDispatcher(state State) *Dispatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dispatcher) notify(name string, alerts ...*Alert) {
|
func (d *Dispatcher) notify(name string, alerts ...*Alert) error {
|
||||||
|
if len(alerts) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
n := &LogNotifier{}
|
n := &LogNotifier{}
|
||||||
i := []interface{}{name, "::"}
|
i := []interface{}{name, "::"}
|
||||||
for _, a := range alerts {
|
for _, a := range alerts {
|
||||||
|
@ -49,7 +53,7 @@ func (d *Dispatcher) Run() {
|
||||||
d.processAlert(alert, m)
|
d.processAlert(alert, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !alert.Resolved {
|
if !alert.Resolved() {
|
||||||
// After the constant timeout update the alert to be resolved.
|
// After the constant timeout update the alert to be resolved.
|
||||||
go func(alert *Alert) {
|
go func(alert *Alert) {
|
||||||
for {
|
for {
|
||||||
|
@ -57,7 +61,7 @@ func (d *Dispatcher) Run() {
|
||||||
time.Sleep(ResolveTimeout)
|
time.Sleep(ResolveTimeout)
|
||||||
|
|
||||||
a := *alert
|
a := *alert
|
||||||
a.Resolved = true
|
a.ResolvedAt = time.Now()
|
||||||
|
|
||||||
if err := d.state.Alert().Add(&a); err != nil {
|
if err := d.state.Alert().Add(&a); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
@ -105,18 +109,16 @@ type Alert struct {
|
||||||
Labels model.LabelSet `json:"labels"`
|
Labels model.LabelSet `json:"labels"`
|
||||||
|
|
||||||
// Extra key/value information which is not used for aggregation.
|
// Extra key/value information which is not used for aggregation.
|
||||||
Payload map[string]string `json:"payload"`
|
Payload map[string]string `json:"payload,omitempty"`
|
||||||
|
Summary string `json:"summary,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Runbook string `json:"runbook,omitempty"`
|
||||||
|
|
||||||
// Short summary of alert.
|
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||||
Summary string `json:"summary"`
|
ResolvedAt time.Time `json:"resolved_at,omitempty"`
|
||||||
Description string `json:"description"`
|
|
||||||
Runbook string `json:"runbook"`
|
|
||||||
|
|
||||||
// When the alert was reported.
|
// The authoritative timestamp.
|
||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp"`
|
||||||
|
|
||||||
// Whether the alert with the given label set is resolved.
|
|
||||||
Resolved bool `json:"resolved"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns the name of the alert. It is equivalent to the "alertname" label.
|
// Name returns the name of the alert. It is equivalent to the "alertname" label.
|
||||||
|
@ -130,6 +132,18 @@ func (a *Alert) Fingerprint() model.Fingerprint {
|
||||||
return a.Labels.Fingerprint()
|
return a.Labels.Fingerprint()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Alert) String() string {
|
||||||
|
s := fmt.Sprintf("%s[%x]", a.Name(), a.Fingerprint())
|
||||||
|
if a.Resolved() {
|
||||||
|
return s + "[resolved]"
|
||||||
|
}
|
||||||
|
return s + "[active]"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Alert) Resolved() bool {
|
||||||
|
return a.ResolvedAt.After(a.CreatedAt)
|
||||||
|
}
|
||||||
|
|
||||||
// aggrGroup aggregates alerts into groups based on
|
// aggrGroup aggregates alerts into groups based on
|
||||||
// common values for a set of labels.
|
// common values for a set of labels.
|
||||||
type aggrGroup struct {
|
type aggrGroup struct {
|
||||||
|
@ -228,7 +242,7 @@ func (ag *aggrGroup) flush() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// TODO(fabxc): only delete if notify successful.
|
// TODO(fabxc): only delete if notify successful.
|
||||||
if a.Resolved {
|
if a.Resolved() {
|
||||||
delete(ag.alerts, fp)
|
delete(ag.alerts, fp)
|
||||||
}
|
}
|
||||||
alerts = append(alerts, a)
|
alerts = append(alerts, a)
|
||||||
|
|
|
@ -5,12 +5,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Notifier interface {
|
type Notifier interface {
|
||||||
|
Name() string
|
||||||
Send(...interface{})
|
Send(...interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogNotifier struct {
|
type LogNotifier struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (*LogNotifier) Name() string {
|
||||||
|
return "default"
|
||||||
|
}
|
||||||
|
|
||||||
func (*LogNotifier) Send(v ...interface{}) {
|
func (*LogNotifier) Send(v ...interface{}) {
|
||||||
log.Infoln(v...)
|
log.Infoln(v...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var DefaultRouteOpts = RouteOpts{
|
var DefaultRouteOpts = RouteOpts{
|
||||||
GroupWait: 1 * time.Minute,
|
GroupWait: 10 * time.Second,
|
||||||
GroupInterval: 1 * time.Minute,
|
GroupInterval: 10 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Routes []*Route
|
type Routes []*Route
|
||||||
|
|
|
@ -125,7 +125,7 @@ func (s *memAlerts) Add(alerts ...*Alert) error {
|
||||||
fp := alert.Fingerprint()
|
fp := alert.Fingerprint()
|
||||||
|
|
||||||
// Last write wins.
|
// Last write wins.
|
||||||
if prev, ok := s.alerts[fp]; !ok || alert.Timestamp.After(prev.Timestamp) {
|
if prev, ok := s.alerts[fp]; !ok || !prev.Timestamp.After(alert.Timestamp) {
|
||||||
s.alerts[fp] = alert
|
s.alerts[fp] = alert
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue