1
// Copyright 2015 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
9
"github.com/juju/errors"
11
"gopkg.in/mgo.v2/bson"
16
defaultGracePeriod = 7 * 24 * time.Hour // 1 week in hours
17
metricsManagerConsecutiveErrorThreshold = 3
18
metricsManagerKey = "metricsManagerKey"
21
// MetricsManager stores data about the state of the metrics manager
22
type MetricsManager struct {
27
type metricsManagerDoc struct {
28
LastSuccessfulSend time.Time `bson:"lastsuccessfulsend"`
29
ConsecutiveErrors int `bson:"consecutiveerrors"`
30
GracePeriod time.Duration `bson:"graceperiod"`
33
// LastSuccessfulSend returns the time of the last successful send.
34
func (m *MetricsManager) LastSuccessfulSend() time.Time {
35
return m.doc.LastSuccessfulSend
38
// ConsecutiveErrors returns the number of consecutive failures.
39
func (m *MetricsManager) ConsecutiveErrors() int {
40
return m.doc.ConsecutiveErrors
43
// GracePeriod returns the current grace period.
44
func (m *MetricsManager) GracePeriod() time.Duration {
45
return m.doc.GracePeriod
48
// MetricsManager returns an existing metricsmanager, or a new one if non exists.
49
func (st *State) MetricsManager() (*MetricsManager, error) {
50
mm, err := st.getMetricsManager()
51
if errors.IsNotFound(err) {
52
return st.newMetricsManager()
53
} else if err != nil {
54
return nil, errors.Trace(err)
59
func (st *State) newMetricsManager() (*MetricsManager, error) {
60
mm := &MetricsManager{
62
doc: metricsManagerDoc{
63
LastSuccessfulSend: time.Time{},
65
GracePeriod: defaultGracePeriod,
69
Id: metricsManagerKey,
70
Assert: txn.DocMissing,
73
err := st.runTransaction(ops)
75
return nil, onAbort(err, errors.NotFoundf("metrics manager"))
80
func (st *State) getMetricsManager() (*MetricsManager, error) {
81
coll, closer := st.getCollection(metricsManagerC)
83
var doc metricsManagerDoc
84
err := coll.FindId(metricsManagerKey).One(&doc)
85
if err == mgo.ErrNotFound {
86
return nil, errors.NotFoundf("metrics manager")
87
} else if err != nil {
88
return nil, errors.Trace(err)
90
return &MetricsManager{st: st, doc: doc}, nil
93
func (m *MetricsManager) updateMetricsManager(update bson.M) error {
96
Id: metricsManagerKey,
97
Assert: txn.DocExists,
100
err := m.st.runTransaction(ops)
101
if err == txn.ErrAborted {
102
err = errors.NotFoundf("metrics manager")
105
return errors.Trace(err)
110
// SetLastSuccessfulSend sets the last successful send time to the input time.
111
func (m *MetricsManager) SetLastSuccessfulSend(t time.Time) error {
112
err := m.updateMetricsManager(
113
bson.M{"$set": bson.M{
114
"lastsuccessfulsend": t.UTC(),
115
"consecutiveerrors": 0,
119
return errors.Trace(err)
121
m.doc.LastSuccessfulSend = t.UTC()
122
m.doc.ConsecutiveErrors = 0
126
func (m *MetricsManager) SetGracePeriod(t time.Duration) error {
128
return errors.New("grace period can't be negative")
130
err := m.updateMetricsManager(
131
bson.M{"$set": bson.M{
136
return errors.Trace(err)
138
m.doc.GracePeriod = t
142
// IncrementConsecutiveErrors adds 1 to the consecutive errors count.
143
func (m *MetricsManager) IncrementConsecutiveErrors() error {
144
err := m.updateMetricsManager(
145
bson.M{"$inc": bson.M{"consecutiveerrors": 1}},
148
return errors.Trace(err)
150
m.doc.ConsecutiveErrors++
154
func (m *MetricsManager) gracePeriodExceeded() bool {
155
// TODO(fwereade): 2016-03-17 lp:1558657
157
t := m.LastSuccessfulSend().Add(m.GracePeriod())
158
return t.Before(now) || t.Equal(now)
161
// MeterStatus returns the overall state of the MetricsManager as a meter status summary.
162
func (m *MetricsManager) MeterStatus() MeterStatus {
163
if m.ConsecutiveErrors() < metricsManagerConsecutiveErrorThreshold {
164
return MeterStatus{MeterGreen, "ok"}
166
if m.gracePeriodExceeded() {
167
return MeterStatus{MeterRed, "failed to send metrics, exceeded grace period"}
169
return MeterStatus{MeterAmber, "failed to send metrics"}